Introduction

In this document we demonstrate methods of community structure analysis by analyzing the community structure of two networks:


Primary School Contact Network

In a previous analysis, we conducted an assortativity analysis of a contact network of primary school students and their teachers gathered by RFID tags, specifically the “Cumulative network day 1, GEXF format” and “Cumulative network day 2, GEXF format” available at: http://www.sociopatterns.org/datasets/primary-school-cumulative-networks/. In that analysis, we combined the two days of data and converted the network to a format readable in igraph, which we use again here.


1. Preparing the Primary School Network

(a) Conversion and Simplification

Gephi was used to convert the gexf file into a format readable by igraph that preserves attributes. We load the converted file below as PS_v1 (version 1) and summarize to show that the data includes 242 vertices and 11438 edges, the vertex attributes (classname and gender) and edge attributes (count and duration) have been preserved, while no layout attributes from Gephi have been added.

PS_v1 <- read_graph("Networks/sp_data_school_day_1_2_multigraph.graphml", 
                 format="graphml")
summary(PS_v1)
IGRAPH e4b4e91 U-W- 242 11438 -- 
+ attr: label (v/c), classname (v/c), gender (v/c), id (v/c), Edge Label (e/c), weight (e/n), duration (e/n), count (e/n), id (e/c)

This is a multigraph: we could not simplify it in Gephi because the “Sum” strategy only sums weights, not other attributes like weight and duration. Here we use simplify with edge.attr.comb set to sum the duration and count attributes as well as weight (which will encode number of days of contact). We print duration and count maximums before and after to ensure they are summed.

print(paste("Before simplify: max count =", max(E(PS_v1)$count), 
            "max duration =", max(E(PS_v1)$duration)), 
      quote=FALSE)
[1] Before simplify: max count = 149 max duration = 9300
PS_v2 <- simplify(PS_v1, edge.attr.comb = list(weight="sum", duration="sum", count="sum", "ignore"))

print(paste("After simplify: max count =", max(E(PS_v2)$count), 
            "max duration =", max(E(PS_v2)$duration)), 
      quote=FALSE)
[1] After simplify: max count = 278 max duration = 15280
summary(PS_v2)
IGRAPH e5940b3 U-W- 242 8316 -- 
+ attr: label (v/c), classname (v/c), gender (v/c), id (v/c), weight (e/n), duration (e/n), count (e/n)

Unlike our previous analysis, in this analysis we will retain teachers, as they are important community members. So we skip that step from Analysis 6.

Filtering Incidental Contacts

A table of the low order contact frequency (rows) and duration (columns) shows that there are many spurious contacts:

table(E(PS_v2)$count, E(PS_v2)$duration)[1:12,1:12]
    
       20   40   60   80  100  120  140  160  180  200  220  240
  1  2855  221   27   10    3    1    0    0    0    0    0    0
  2     0  807  163   46   20    5    4    5    0    0    0    0
  3     0    0  347  150   47   19    8    5    2    1    1    1
  4     0    0    0  191   89   51   21   13   10    3    2    0
  5     0    0    0    0  109   86   47   27   15    7    3    1
  6     0    0    0    0    0   83   56   37   23   16    9    3
  7     0    0    0    0    0    0   38   61   42   30   14    2
  8     0    0    0    0    0    0    0   38   40   28   16   13
  9     0    0    0    0    0    0    0    0   23   32   33   23
  10    0    0    0    0    0    0    0    0    0   15   20   22
  11    0    0    0    0    0    0    0    0    0    0   12   23
  12    0    0    0    0    0    0    0    0    0    0    0   11

Filtering is based on the following observations and criteria:

  • We decide that a continuous interaction of 60 seconds is sufficient to indicate real contact between students.

  • The large numbers of brief interactions in table positions 1,20, 1,40 and 2,40 should be removed, but this is not sufficient for the following reason.

  • The minimum resolution of the RFID tags is 20 seconds (“20” is recorded even if students were in contact for only 1 second). Thus, values on the diagonal where duration = count*20 could have been obtained by students passing by each other count number of times with proximity lasting as little as however many seconds are needed for the tags to communicate, and cannot involve interactions of more than 20 seconds.

  • To exclude trivial contacts we require that at least one contact have duration of 60 seconds or more. (We also allow two contacts of 40 seconds or more because these will be hard to distinguish with this aggregated data.)

  • We accomplish this by requiring that duration >= (count*20) + 40. The count*20 provides the baseline number one might get with count spurious interactions. By adding 40, this requires that at least one of these count contacts is 60 seconds (20 + 40), or two of them are at least 40 seconds.

This policy will remove most of the edges on the first two nonzero values in each row (the first two diagonals), and leads to cleaner visualization in Gephi.

We apply this policy below, naming the new graph PSF for PS Filtered. (Variations on this policy have been tried with substantially similar results in the analysis that follows.)

PSF <- delete_edges(PS_v2, E(PS_v2)[duration < (count*20) + 40])
PSF$name <- "Filtered Primary School Contacts"

# Expecting 242 vertices 2759 edges
summary(PSF)
IGRAPH e9baf21 U-W- 242 2759 -- Filtered Primary School Contacts
+ attr: name (g/c), label (v/c), classname (v/c), gender (v/c), id (v/c), weight (e/n), duration (e/n), count (e/n)

A frequency table of updated counts and durations is shown below.

table(count=E(PSF)$count, duration=E(PSF)$duration)[1:10,1:12]
     duration
count 60 80 100 120 140 160 180 200 220 240 260 280
   1  27 10   3   1   0   0   0   0   0   0   0   0
   2   0 46  20   5   4   5   0   0   0   0   0   0
   3   0  0  47  19   8   5   2   1   1   1   0   1
   4   0  0   0  51  21  13  10   3   2   0   2   1
   5   0  0   0   0  47  27  15   7   3   1   3   1
   6   0  0   0   0   0  37  23  16   9   3   2   3
   7   0  0   0   0   0   0  42  30  14   2   5   1
   8   0  0   0   0   0   0   0  28  16  13  10   7
   9   0  0   0   0   0   0   0   0  33  23  10   9
   10  0  0   0   0   0   0   0   0   0  22  20  20

Adding Grade Attribute

We would like to analyze by grade level, but grade is coded only indirectly as classname. Below we a new attribute called ‘grade’ and give it appropriate values by conversion of the ‘classname’ attribute and provide a frequency table of the new grade attribute.

V(PSF)$grade <- substr(V(PSF)$classname, 1, 1)
table(V(PSF)$grade)

 1  2  3  4  5  T 
48 49 45 44 46 10 

Notice that unlike the previous analysis the grade attribute includes “T” for Teacher, a non-numeric value. This will affect how we compute assortativity.

Simplifing Attribute Labels for Visualization

We shorten these vertex attributes so they take less space when visualized, changing $gender “Unknown” to “U” and $classname “Teachers” to “T”, resulting in the following sets of values:

V(PSF)$gender <- replace(V(PSF)$gender, V(PSF)$gender=="Unknown", "U")
sort(unique(V(PSF)$gender))
[1] "F" "M" "U"
V(PSF)$classname <- replace(V(PSF)$classname, 
                            V(PSF)$classname=="Teachers", "T")
sort(unique(V(PSF)$classname))
 [1] "1A" "1B" "2A" "2B" "3A" "3B" "4A" "4B" "5A" "5B" "T" 

2. Computing and Comparing Partitions

Below we compute partitions using the InfoMap and Louvain community detection methods, and compare them to each other and two node attributes that may predict connectivity, Classname and Grade. All of these partition the network. We ask: how well does each partitioning capture the connectivity of the nodes? how similar are the partitions to each other?

(a) Community Detection Partitions

InfoMap

In order to account for the wide variation in duration of contacts, we use contact duration as edge weights in this analysis. The resulting community sizes are displayed.

PSF.infomap <- cluster_infomap(PSF, e.weights= E(PSF)$duration)
sizes(PSF.infomap)
Community sizes
 1  2  3  4  5  6  7  8  9 10 
24 24 22 24 26 22 23 27 26 24 

Louvain

Again, we use contact duration as edge weights in this analysis. The resulting community sizes are displayed.

PSF.louvain <- cluster_louvain(PSF, weights = E(PSF)$duration)
sizes(PSF.louvain)
Community sizes
 1  2  3  4  5  6 
24 47 44 26 50 51 
(b) Comparison by Modularity and Assortativity

The attribute based and computed partitions are compared on these metrics:

# Reminder: unlike Analysis 6, grade now includes "T"  
 rbind(
   tibble(metric = "Modularity",
          Classname = modularity(PSF, as.integer(as.factor(V(PSF)$classname))),
          Grade     = modularity(PSF, as.integer(as.factor(V(PSF)$grade))),
          Louvain   = modularity(PSF.louvain),
          InfoMap   = modularity(PSF.infomap),
   ),
          
   tibble(metric = "Assortativity",
          Classname = assortativity_nominal(PSF, as.integer(as.factor(V(PSF)$classname))),
          Grade     = assortativity_nominal(PSF, as.integer(as.factor(V(PSF)$grade))),
          Louvain   = assortativity(PSF, membership(PSF.louvain)),
          InfoMap   = assortativity(PSF, membership(PSF.infomap))
   )
 )

Explanation of Rank Ordering of Metrics

Assortativity is modularity scaled such that 1 is the maximum value it can have. We might expect that this means that assortativity is always larger, yet we see that this is not the case for Louvain and InfoMap.

This would indicate that modularity on Louvain and InfoMap are returning that there are slightly more communities detected than how well Louvain and InfoMap are in assortativeness. Maybe it is because we’re applying assortativity on the specific communities of PSF.louvain or PSF.infomap. Modularity measures how separated are the different vertex types from each other so assuming my numbers are correct, the amount of communities that are present is more than the amount of connected vertices that have the same labels or similar assigned values. Or perhaps it is because we considered the weights for both Louvain and Infomap to be based on duration. Although there isn’t a lot of connections, the weights of duration for these connections are finding more communities than usual through modularity optimization and flow optimization.

From the previous assignment, I remember that PSF had different grade levels so based on the information above, most students are in communities (i.e., grade), but they don’t talk to other students in other grades as much, and they probably don’t talk to everyone in their own grade either. This could possibly explain the previous question on why assortativity is lower. (I use this reasoning for the question below as well).

How Well Partitions Reflect Network Connectivity

Setting these differences aside, these metrics indicate how well each partition reflects the connectivity of the network as follows.

Modularity indicates that majority of the nodes in PSF belong to a community if Louvain and InfoMap returned 0.70. You would assume then there would be a lot of nodes connected to each other but that isn’t the case. Assortativity indicates that although majority of the nodes are in communities, the degree of correlation between connected nodes is lower than the amount of communities there are. Or in other words, the preference for a network’s nodes to attach to others that are similar is lower than the amount of communities present.

I assume this means that the network does not have many nodes crossing over to other communities but rather stays within their own communities; and even then, the nodes probably don’t talk as much to other nodes within their own communities. Reasoning based on previous question above.

From the previous assignment, I remember that PSF had different grade levels so based on the information above, most students are in communities (i.e., grade), but they don’t talk to other students in other grades as much, and they probably don’t talk to everyone in their own grade either. This could possibly explain the previous question on why assortativity is lower.

But this leaves open the question of how these partitions compare to each other.

(c) Comparison by Normalized Mutual Information

Normalized Mutual Information tells us how much information a pair of partitioning (interpreted as random variables) share with each other. It is normalized to [0,1], making it like a correlation coefficient. (https://en.wikipedia.org/wiki/Mutual_information)


# Using any approach you prefer, make a correlation matrix of this form:
# partition  Classname  Grade      InfoMap    Louvain 
# Classname  x.xxxxx    x.xxxxx    x.xxxxx    x.xxxxx
# Grade      x.xxxxx    x.xxxxx    x.xxxxx    x.xxxxx
# InfoMap    x.xxxxx    x.xxxxx    x.xxxxx    x.xxxxx
# Louvain    x.xxxxx    x.xxxxx    x.xxxxx    x.xxxxx

# I ended up using a conventional programming for-loop approach. There
# is probably an elegant R-style approach, but the tibble-based
# solution I constructed required repeating code that constructs
# membership lists, which did not seem any more elegant than a loop.


rbind(
   tibble(parition = "Classname",
          Classname = compare(V(PSF)$classname, V(PSF)$classname, method = "nmi"),
          Grade     = compare(V(PSF)$classname, V(PSF)$grade, method="nmi"),
          Louvain   = compare(V(PSF)$classname, membership(PSF.louvain), method="nmi"),
          InfoMap   = compare(V(PSF)$classname, membership(PSF.infomap), method="nmi"),
   ),
          
   tibble(parition = "Grade",
          Classname = compare(V(PSF)$grade, V(PSF)$classname, method = "nmi"),
          Grade     = compare(V(PSF)$grade, V(PSF)$grade, method="nmi"),
          Louvain   = compare(V(PSF)$grade, membership(PSF.louvain), method="nmi"),
          InfoMap   = compare(V(PSF)$grade, membership(PSF.infomap), method="nmi"),
   ),
   
   tibble(parition = "Louvain",
          Classname = compare(membership(PSF.louvain), V(PSF)$classname, method = "nmi"),
          Grade     = compare(membership(PSF.louvain), V(PSF)$grade, method="nmi"),
          Louvain   = compare(membership(PSF.louvain), membership(PSF.louvain), method="nmi"),
          InfoMap   = compare(membership(PSF.louvain), membership(PSF.infomap), method="nmi"),
   ),
   
   tibble(parition = "Infomap",
          Classname = compare(membership(PSF.infomap), V(PSF)$classname, method = "nmi"),
          Grade     = compare(membership(PSF.infomap), V(PSF)$grade, method="nmi"),
          Louvain   = compare(membership(PSF.infomap), membership(PSF.louvain), method="nmi"),
          InfoMap   = compare(membership(PSF.infomap), membership(PSF.infomap), method="nmi"),
   )
 )

Because the table above essentially represents a multiplication matrix you’re going to see repeating values for the the same (x,y) and (y,x). However, if we ignore that for a second, consider the the highest values from our comparison table. Infomap and classname surprisingly does well as the highest distance between the two community structures at 0.93 but not grade which is the lowest out of all comparisons at 0.76. The inverse is somewhat true for louvain. Louvain and classname is relatively low at 0.79 whilst louvain and grade is relatively mid at 0.87.

Perhaps we can consider the relationship that louvain is to classname as infomap is to grade. Louvain and classname has low correlation because louvain is considered more generic whilst infomap and grade has less correlation because infomap is considered more “granular” and picks out individual classnames better.


3. Examining Results in Gephi

Visualizations in Gephi will be used to interpret the partitions.

(a) Exporting Results to Gephi

Community membership is assigned to vertices under attributes $louvain and $infomap.

 V(PSF)$louvain <- membership(PSF.louvain)
 V(PSF)$infomap <- membership(PSF.infomap)

In Gephi, we want to visualize edges weighted by edge attribute ‘duration’. But Gephi does not let us specify the location of the weights, and always uses the ‘weight’ attribute. So, we want to write duration into the weight attribute. However, inspection reveals that there are two values: 1 and 2. These come from collapsing the multigraph, and indicate the number of days on which two students had contact. We’ll first preserve this information in case it is useful in ‘days’.

sort(unique(E(PSF)$weight))
[1] 1 2
 E(PSF)$days <- E(PSF)$weight
 E(PSF)$weight <- E(PSF)$duration
summary(PSF)
IGRAPH e9baf21 U-W- 242 2759 -- Filtered Primary School Contacts
+ attr: name (g/c), label (v/c), classname (v/c), gender (v/c), id (v/c), grade (v/c), louvain (v/n), infomap (v/n), weight (e/n), duration
| (e/n), count (e/n), days (e/n)

Then we write out a graphml file for inspection in Gephi.

write_graph(PSF, "Networks/Primary-School-Students-Filtered.graphml", format="graphml")
(b) Spatialized Visualization in Gephi

A spatialized visualization of the network was constructed in Gephi using Force Atlas 2 and the following parameters:

  • Nodes sized by degree and labeled with their classname and gender.
  • Lin-Log mode
  • Prevent Overlap filter
  • Edge Weight Influence set to 0 (otherwise the large duration weights will compress the layout)
  • Gravity 2.0 to get a compact but not crowded visualization.

Nodes were labeled with classname and gender. Please see the enclosed Gephi project Primary-School-Communities.gephi for high resolution images. Results are illustrated in the following screen captures.

(c) Visualization of Partitions

Below we visualize partitioning by classname, grade, InfoMap, and Louvain by coloring the above spatialized visualization by these partitions. Color keys are provided. We organize the results to highlight similarities, but leave the discussion for the next section.

Partition by Classname

Partition by Grade

Partition by infomap

Partition by louvain

(d) Discussion: Comparison of Partitions

We discuss three comparisons:

Comparing Community Detection Methods to Each-other

When we look at the visulizations between Louvain and Infomap the obvious difference is that louvain returned that 6 communities were detected whilst infomap returned that 10 communities that were detected. Probably because infomap is better at detecting that certain students prefer to talk to a members of the same specific grade (2A, 2B) but louvain is detecting that there are enough interactions between students of the same grade that it considers all of them to be within the same community with an exception for grade 1 where it successfully detected that 1A (1.0) and 1B (4.0) are technically separate communities. This isn’t entirely wrong but I guess you could interpret that as, “less accurate.”

Comparing Community Detection Methods to Classname and Grade

When we consider the visualizations between the community detection methods to classname and grade we see that my assumptions from the previous question is correct. Infomap does a good job detecting that although there are 5 grade levels, there is also a sub division between grade XA and XB where you can consider this another set of communities. Louvain only detected this with grade 1 where it detected a difference in community between 1A (1.0), and 1B (4.0).

(e) Observations about Actor Behavior

Based on all of the above analyses, we can draw these conclusions about student and teacher behavior:

Observations about Collective Behavior

Interestingly, if you consider the node sizes between students and teachers, teachers are visually smaller in physical size. This indicates that although student and teacher connections are guaranteed, or it is guaranteed for a student node to have an edge connection with a teacher node, this doesn’t entirely mean that teachers are the most popular. Teacher nodes themselves aren’t even acting as bridges to other communities but rather stick to their own specific grade (i.e., 1A, 1B) communities.

The student nodes that border the communities act as their own bridges that talk to other communities. This is supported by their physical size being noticeably bigger as size is based on degree, and the edge connections are dense when attaching to nodes in other communities. There’s probably a lot of student cross over behavior because of similar school activities (i.e., breakfast, recess, lunch, lunch recess, same teachers every grade, extracurriculars). However, also consider that grade XA and XB probably share similar classes. If I recall from elementary school, although we had different teachers, there were non-main subject classes (i.e., music, hula, arts, P.E.) where the entire grade level was in a single class. The data set is small enough to show that there is about 20 students per classroom so it’s entirely possible to have a joint class session with 40 students. Perfect way to allow students to create more “edges” and have the students that border communities act as “popular” kids.

Observations about Salient Individuals or Pairs

There are cases where the edges are thicker than usual in visual appearance indicating that certain students or pairs of students have a stronger connection. Because the weights are determined by duration, I would assume these strong connections indicate that the students are probably real-life friends and not just friends at school (i.e., play outside of school whether it be real-life hanging or gaming online). Especially in the top border of 1B of the classname visualization, you can see loops between students with thick blue edges. These probably indicate strong friend groups which is technically a community of their own.


Hero Coappearance Network

In this section we examine a network derived from the Marvel Social Network Networks of super heroes, constructed by Cesc Rosselló, Ricardo Alberich, and Joe Miro (http://bioinfo.uib.es/~joemiro/marvel.html). The original network connects comic book heroes to the issues they appeared in. We work with a projection onto heroes, with links between heroes weighted by the number of issues they co-appeared in. We are interested in identifying and interpreting several of the largest “communities” of heroes in this network.


4. Preparing the Hero Coappearance Network

The network is read in and summarized below.

Heroes <- read_graph("Networks/Hero-Coappearance-Network.graphml", 
                 format="graphml")
summary(Heroes)
IGRAPH 17539f2 U-W- 6439 167103 -- 
+ attr: label (v/c), id (v/c), Edge Label (e/c), weight (e/n), id (e/c)

We compute the Louvain and InfoMap partitions and annotate vertices with their partition membership below. We also compute node centrality metrics on the full network, to aid in interpretation (by comparison to partition-specific centrality metrics to be computed in Gephi). The resulting annotated network is shown below and written out for visualization in Gephi.

 Heroes.louvain     <- cluster_louvain(Heroes, weights= E(Heroes)$weight)
 Heroes.infomap     <- cluster_infomap(Heroes, e.weights = E(Heroes)$weight)
 V(Heroes)$louvain  <- membership(Heroes.louvain)
 V(Heroes)$infomap  <- membership(Heroes.infomap)
 V(Heroes)$degree   <- degree(Heroes)
 V(Heroes)$wdegree  <- strength(Heroes, weights=E(Heroes)$weight)
 V(Heroes)$pagerank <- page_rank(Heroes)$vector
 summary(Heroes)
IGRAPH 17539f2 U-W- 6439 167103 -- 
+ attr: label (v/c), id (v/c), louvain (v/n), infomap (v/n), degree (v/n), wdegree (v/n), pagerank (v/n), Edge Label (e/c), weight (e/n), id
| (e/c)
 write_graph(Heroes,"Hero-Communities.graphml", format="graphml")

5. Finding Crossing Vertices

Crossing edges are edges that cross partitions. The vertices at the endpoint of these edges are of interest, especially if they participate in many crossings, as they may be involved in multiple communities beyond the one that the partition assigned to them. Below we display the top 20 of vertices ranked by the number of crossing edges incident on them in each of the two partitions:

# Display the top 20 crossing vertices and the number of edges via
# which they connect to others outside their partition, for both
# Louvain and Infomap. I suggest taking these steps

# Compute crossings for Louvain, sorted decreasing by crossing: 

# Compute crossings for Infomap, sorted decreasing by crossing: 

# Display in combined tibble: 


 tibble(Hero_in_Louvain = V(Heroes)[sort(table(V(Heroes)[ends(Heroes, which(crossing(Heroes.louvain, Heroes)))]$id),decreasing=TRUE)[1:20]]$label,
        Cross_Count_L   = sort(table(V(Heroes)[ends(Heroes, which(crossing(Heroes.louvain, Heroes)))]$id),decreasing=TRUE)[1:20],
        Hero_in_Infomap = V(Heroes)[sort(table(V(Heroes)[ends(Heroes, which(crossing(Heroes.infomap, Heroes)))]$id),decreasing=TRUE)[1:20]]$label,
        Cross_Count_I   = sort(table(V(Heroes)[ends(Heroes, which(crossing(Heroes.infomap, Heroes)))]$id), decreasing=TRUE)[1:20]
 )

6. Interpreting Communities in Gephi

(a) Visualization in Gephi

The network has been read into Gephi and a spatialized visualization has been constructed, but is too complex to show here. Excerpts will be taken as needed to illustrate the following interpretations of partitions.

write_graph(Heroes, file="Networks/Hero-Coappearance-Network.graphml",format = "graphml")
(b) Partitions of Interest

The following partitions have clear interpretations in terms of the comic hero “universe”, and thereby illustrate the power of community detection methods for finding meaningful subgraphs based on structural information alone.

The visualization was difficult but I filtered out enough things to find 3 communities which are probably the most notable and central. This figure was made by setting node size to eigenvector centrality, coloring by infomap and choosing 10 arbitrary colors. I then set everything that isn’t the big 3 communities to white and filtered by partition infomap.

First Partition

This figure was made by setting node size to eigenvector centrality, coloring by infomap and choosing 10 arbitrary colors. I then set everything that isn’t the big 3 communities to white and filtered by partition infomap.

For this particular partition with infomap colored in pink, we see a community of general “main” marvel villains. This is supported by the fact we see repeating titles of “[insert marvel character name] Doppelganger”. In the comics there were a lot of clone stories where the characters have to face themselves. Towards the middle right of the figure we see popular villains such as Thanos, Galactus, Death, and further down we can see Surfer. These are all marvel characters that have prominent cameos in the marvel cinematic universe as villains as well.

Second Partition

This figure was made by setting node size to eigenvector centrality, coloring by infomap and choosing 10 arbitrary colors. I then set everything that isn’t the big 3 communities to white and filtered by partition infomap.

In this particular partition colored in red, we see evidence that these characters are main members of Marvel Avengers or heavily related to the Avengers with notable names such as Scarlet Witch, Vision, Hawk, Iron Man, , Captain America, Hulk, Wasp, Quicksilver, Jarvis, etc.

Third Partition

This figure was made by setting node size to eigenvector centrality, coloring by infomap and choosing 10 arbitrary colors. I then set everything that isn’t the big 3 communities to white and filtered by partition infomap.

This one I got lucky. I read some comics and watched the original Fantastic 4 movies to immediately know the character names right under the previous two communities. Based on the names, we see evidence that this community is based on the Fantastic 4 storyline/series (i.e., Dr. Doom, Invisible Woman, Human Torch, Mr. Fantastic, Thing, etc.)

(c) Implications of Crossing Vertices

Comparing the high-centrality (important) hero figures in the above partitions to the crossing vertices analysis performed previously, we see that many heroes central in a single partition are also high on the crossing vertices list.

This fact suggests that in the comic universe, these heroes and villains alike, play a role in communities and sub communities. Our infomap interpretation of the comic book data set shows that although these characters have a main community they participate in, notably Marvel villains, Marvel Avengers, and Fantastic 4, it doesn’t necessarily mean they are restricted to their own community. Alot of characters cross over themselves as team members or villains with comic issues that have to provide fresh plot lines, cross over plot lines, dark plot lines, fan service, multi-verse plot lines, time travel plot lines, and the infamous capcom vs marvel series. The crossing edges and crossing vertices is an indication of that.

It also suggests a limitation of the above community detection methods: These community detection methods only show surface level communities and doesn’t show the intricate details and cross over plot lines written by the comic book writers and artists as a lot of characters in my visualization probably has an undetected community (comic series) with a rich plot line showing that they were in fact apart of a whole different set of communities.


Pau

LS0tDQp0aXRsZTogIlBhcmsgQW5hbHlzaXMgNyBDb21tdW5pdHkgRGV0ZWN0aW9uIg0KYXV0aG9yOiAiSW4gV29vIFBhcmsiDQpkYXRlOiAiNC8wOC8yMDIyIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGRmX3ByaW50OiBwYWdlZA0KICBodG1sX25vdGVib29rOiANCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBkZl9wcmludDogcGFnZWQNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRSwgZWNobz1GQUxTRX0NCnJlcXVpcmUoImtuaXRyIikNCm9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KbGlicmFyeShpZ3JhcGgpDQpsaWJyYXJ5KHRpYmJsZSkNCiMgRm9yIGluY2x1ZGluZyBpbWFnZXMgb2YgdGhlc2UgdHlwZXMNCmxpYnJhcnkoanBlZykgDQpsaWJyYXJ5KHBuZykNCiMgVXRpbGl0aWVzIG1heSBiZSBhZGRlZCBoZXJlLg0KYGBgDQoNCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KIyMjIEludHJvZHVjdGlvbiANCg0KSW4gdGhpcyBkb2N1bWVudCB3ZSBkZW1vbnN0cmF0ZSBtZXRob2RzIG9mIGNvbW11bml0eSBzdHJ1Y3R1cmUgYW5hbHlzaXMgYnkgYW5hbHl6aW5nIHRoZSBjb21tdW5pdHkgc3RydWN0dXJlIG9mIHR3byBuZXR3b3JrczogDQoNCiogQSBwcmltYXJ5IHNjaG9vbCBjb250YWN0IG5ldHdvcmssIHdpdGggdGVhY2hlcnMgaW5jbHVkZWQgDQoqIEEgY28tYXBwZWFyYW5jZSBuZXR3b3JrIG9mIGNvbWljIGJvb2sgaGVyb2VzLiANCg0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQojIyMgUHJpbWFyeSBTY2hvb2wgQ29udGFjdCBOZXR3b3JrIA0KDQpJbiBhIHByZXZpb3VzIGFuYWx5c2lzLCB3ZSBjb25kdWN0ZWQgYW4gYXNzb3J0YXRpdml0eSBhbmFseXNpcyBvZiBhIGNvbnRhY3QgbmV0d29yayBvZiBwcmltYXJ5IHNjaG9vbCBzdHVkZW50cyBhbmQgdGhlaXIgdGVhY2hlcnMgZ2F0aGVyZWQgYnkgUkZJRCB0YWdzLCBzcGVjaWZpY2FsbHkgdGhlICJDdW11bGF0aXZlIG5ldHdvcmsgZGF5IDEsIEdFWEYgZm9ybWF0IiBhbmQgIkN1bXVsYXRpdmUgbmV0d29yayBkYXkgMiwgR0VYRiBmb3JtYXQiIGF2YWlsYWJsZSBhdDogaHR0cDovL3d3dy5zb2Npb3BhdHRlcm5zLm9yZy9kYXRhc2V0cy9wcmltYXJ5LXNjaG9vbC1jdW11bGF0aXZlLW5ldHdvcmtzLy4gSW4gdGhhdCBhbmFseXNpcywgd2UgY29tYmluZWQgdGhlIHR3byBkYXlzIG9mIGRhdGEgYW5kIGNvbnZlcnRlZCB0aGUgbmV0d29yayB0byBhIGZvcm1hdCByZWFkYWJsZSBpbiBpZ3JhcGgsIHdoaWNoIHdlIHVzZSBhZ2FpbiBoZXJlLiANCg0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQojIyMjIDEuIFByZXBhcmluZyB0aGUgUHJpbWFyeSBTY2hvb2wgTmV0d29yaw0KDQojIyMjIyAoYSkgQ29udmVyc2lvbiBhbmQgU2ltcGxpZmljYXRpb24gDQoNCkdlcGhpIHdhcyB1c2VkIHRvIGNvbnZlcnQgdGhlIGdleGYgZmlsZSBpbnRvIGEgZm9ybWF0IHJlYWRhYmxlIGJ5IGlncmFwaCB0aGF0IHByZXNlcnZlcyBhdHRyaWJ1dGVzLiBXZSBsb2FkIHRoZSBjb252ZXJ0ZWQgZmlsZSBiZWxvdyBhcyBQU192MSAodmVyc2lvbiAxKSBhbmQgc3VtbWFyaXplIHRvIHNob3cgdGhhdCB0aGUgZGF0YSBpbmNsdWRlcyAyNDIgdmVydGljZXMgYW5kIDExNDM4IGVkZ2VzLCB0aGUgdmVydGV4IGF0dHJpYnV0ZXMgKGNsYXNzbmFtZSBhbmQgZ2VuZGVyKSBhbmQgZWRnZSBhdHRyaWJ1dGVzIChjb3VudCBhbmQgZHVyYXRpb24pIGhhdmUgYmVlbiBwcmVzZXJ2ZWQsIHdoaWxlIG5vIGxheW91dCBhdHRyaWJ1dGVzIGZyb20gR2VwaGkgaGF2ZSBiZWVuIGFkZGVkLiANCg0KDQpgYGB7cn0NClBTX3YxIDwtIHJlYWRfZ3JhcGgoIk5ldHdvcmtzL3NwX2RhdGFfc2Nob29sX2RheV8xXzJfbXVsdGlncmFwaC5ncmFwaG1sIiwgDQogICAgICAgICAgICAgICAgIGZvcm1hdD0iZ3JhcGhtbCIpDQpzdW1tYXJ5KFBTX3YxKQ0KYGBgDQoNClRoaXMgaXMgYSBtdWx0aWdyYXBoOiB3ZSBjb3VsZCBub3Qgc2ltcGxpZnkgaXQgaW4gR2VwaGkgYmVjYXVzZSB0aGUgIlN1bSIgc3RyYXRlZ3kgb25seSBzdW1zIHdlaWdodHMsIG5vdCBvdGhlciBhdHRyaWJ1dGVzIGxpa2Ugd2VpZ2h0IGFuZCBkdXJhdGlvbi4gSGVyZSB3ZSB1c2Ugc2ltcGxpZnkgd2l0aCBlZGdlLmF0dHIuY29tYiBzZXQgdG8gc3VtIHRoZSBkdXJhdGlvbiBhbmQgY291bnQgYXR0cmlidXRlcyBhcyB3ZWxsIGFzIHdlaWdodCAod2hpY2ggd2lsbCBlbmNvZGUgbnVtYmVyIG9mIGRheXMgb2YgY29udGFjdCkuIFdlIHByaW50IGR1cmF0aW9uIGFuZCBjb3VudCBtYXhpbXVtcyBiZWZvcmUgYW5kIGFmdGVyIHRvIGVuc3VyZSB0aGV5IGFyZSBzdW1tZWQuIA0KDQpgYGB7cn0NCnByaW50KHBhc3RlKCJCZWZvcmUgc2ltcGxpZnk6IG1heCBjb3VudCA9IiwgbWF4KEUoUFNfdjEpJGNvdW50KSwgDQogICAgICAgICAgICAibWF4IGR1cmF0aW9uID0iLCBtYXgoRShQU192MSkkZHVyYXRpb24pKSwgDQogICAgICBxdW90ZT1GQUxTRSkNClBTX3YyIDwtIHNpbXBsaWZ5KFBTX3YxLCBlZGdlLmF0dHIuY29tYiA9IGxpc3Qod2VpZ2h0PSJzdW0iLCBkdXJhdGlvbj0ic3VtIiwgY291bnQ9InN1bSIsICJpZ25vcmUiKSkNCg0KcHJpbnQocGFzdGUoIkFmdGVyIHNpbXBsaWZ5OiBtYXggY291bnQgPSIsIG1heChFKFBTX3YyKSRjb3VudCksIA0KICAgICAgICAgICAgIm1heCBkdXJhdGlvbiA9IiwgbWF4KEUoUFNfdjIpJGR1cmF0aW9uKSksIA0KICAgICAgcXVvdGU9RkFMU0UpDQpzdW1tYXJ5KFBTX3YyKQ0KYGBgDQoNClVubGlrZSBvdXIgcHJldmlvdXMgYW5hbHlzaXMsIGluIHRoaXMgYW5hbHlzaXMgKndlIHdpbGwgcmV0YWluIHRlYWNoZXJzKiwgYXMgdGhleSBhcmUgaW1wb3J0YW50IGNvbW11bml0eSBtZW1iZXJzLiBTbyB3ZSBza2lwIHRoYXQgc3RlcCBmcm9tIEFuYWx5c2lzIDYuIA0KDQoqKkZpbHRlcmluZyBJbmNpZGVudGFsIENvbnRhY3RzKioNCg0KQSB0YWJsZSBvZiB0aGUgbG93IG9yZGVyIGNvbnRhY3QgZnJlcXVlbmN5IChyb3dzKSBhbmQgZHVyYXRpb24gKGNvbHVtbnMpIHNob3dzIHRoYXQgdGhlcmUgYXJlIG1hbnkgc3B1cmlvdXMgY29udGFjdHM6IA0KDQpgYGB7cn0NCnRhYmxlKEUoUFNfdjIpJGNvdW50LCBFKFBTX3YyKSRkdXJhdGlvbilbMToxMiwxOjEyXQ0KYGBgDQoNCkZpbHRlcmluZyBpcyBiYXNlZCBvbiB0aGUgZm9sbG93aW5nIG9ic2VydmF0aW9ucyBhbmQgY3JpdGVyaWE6DQoNCiogV2UgZGVjaWRlIHRoYXQgYSBjb250aW51b3VzIGludGVyYWN0aW9uIG9mIDYwIHNlY29uZHMgaXMgc3VmZmljaWVudCB0byBpbmRpY2F0ZSByZWFsIGNvbnRhY3QgYmV0d2VlbiBzdHVkZW50cy4NCg0KKiBUaGUgbGFyZ2UgbnVtYmVycyBvZiBicmllZiBpbnRlcmFjdGlvbnMgaW4gdGFibGUgcG9zaXRpb25zIDEsMjAsIDEsNDAgYW5kIDIsNDAgc2hvdWxkIGJlIHJlbW92ZWQsIGJ1dCB0aGlzIGlzIG5vdCBzdWZmaWNpZW50IGZvciB0aGUgZm9sbG93aW5nIHJlYXNvbi4NCg0KKiBUaGUgbWluaW11bSByZXNvbHV0aW9uIG9mIHRoZSBSRklEIHRhZ3MgaXMgMjAgc2Vjb25kcyAo4oCcMjDigJ0gaXMgcmVjb3JkZWQgZXZlbiBpZiBzdHVkZW50cyB3ZXJlIGluIGNvbnRhY3QgZm9yIG9ubHkgMSBzZWNvbmQpLiBUaHVzLCB2YWx1ZXMgb24gdGhlIGRpYWdvbmFsIHdoZXJlIGR1cmF0aW9uID0gY291bnRcKjIwIGNvdWxkIGhhdmUgYmVlbiBvYnRhaW5lZCBieSBzdHVkZW50cyBwYXNzaW5nIGJ5IGVhY2ggb3RoZXIgY291bnQgbnVtYmVyIG9mIHRpbWVzIHdpdGggcHJveGltaXR5IGxhc3RpbmcgYXMgbGl0dGxlIGFzIGhvd2V2ZXIgbWFueSBzZWNvbmRzIGFyZSBuZWVkZWQgZm9yIHRoZSB0YWdzIHRvIGNvbW11bmljYXRlLCBhbmQgY2Fubm90IGludm9sdmUgaW50ZXJhY3Rpb25zIG9mIG1vcmUgdGhhbiAyMCBzZWNvbmRzLg0KDQoqIFRvIGV4Y2x1ZGUgdHJpdmlhbCBjb250YWN0cyB3ZSByZXF1aXJlIHRoYXQgYXQgbGVhc3Qgb25lIGNvbnRhY3QgaGF2ZSBkdXJhdGlvbiBvZiA2MCBzZWNvbmRzIG9yIG1vcmUuIChXZSBhbHNvIGFsbG93IHR3byBjb250YWN0cyBvZiA0MCBzZWNvbmRzIG9yIG1vcmUgYmVjYXVzZSB0aGVzZSB3aWxsIGJlIGhhcmQgdG8gZGlzdGluZ3Vpc2ggd2l0aCB0aGlzIGFnZ3JlZ2F0ZWQgZGF0YS4pDQoNCiogV2UgYWNjb21wbGlzaCB0aGlzIGJ5IHJlcXVpcmluZyB0aGF0IGR1cmF0aW9uID49IChjb3VudFwqMjApICsgNDAuIFRoZSBjb3VudFwqMjAgcHJvdmlkZXMgdGhlIGJhc2VsaW5lIG51bWJlciBvbmUgbWlnaHQgZ2V0IHdpdGggY291bnQgc3B1cmlvdXMgaW50ZXJhY3Rpb25zLiBCeSBhZGRpbmcgNDAsIHRoaXMgcmVxdWlyZXMgdGhhdCBhdCBsZWFzdCBvbmUgb2YgdGhlc2UgY291bnQgY29udGFjdHMgaXMgNjAgc2Vjb25kcyAoMjAgKyA0MCksIG9yIHR3byBvZiB0aGVtIGFyZSBhdCBsZWFzdCA0MCBzZWNvbmRzLg0KDQpUaGlzIHBvbGljeSB3aWxsIHJlbW92ZSBtb3N0IG9mIHRoZSBlZGdlcyBvbiB0aGUgZmlyc3QgdHdvIG5vbnplcm8gdmFsdWVzIGluIGVhY2ggcm93ICh0aGUgZmlyc3QgdHdvIGRpYWdvbmFscyksIGFuZCBsZWFkcyB0byBjbGVhbmVyIHZpc3VhbGl6YXRpb24gaW4gR2VwaGkuDQoNCldlIGFwcGx5IHRoaXMgcG9saWN5IGJlbG93LCBuYW1pbmcgdGhlIG5ldyBncmFwaCBQU0YgZm9yIFBTIEZpbHRlcmVkLiAoVmFyaWF0aW9ucyBvbiB0aGlzIHBvbGljeSBoYXZlIGJlZW4gdHJpZWQgd2l0aCBzdWJzdGFudGlhbGx5IHNpbWlsYXIgcmVzdWx0cyBpbiB0aGUgYW5hbHlzaXMgdGhhdCBmb2xsb3dzLikNCg0KYGBge3J9DQpQU0YgPC0gZGVsZXRlX2VkZ2VzKFBTX3YyLCBFKFBTX3YyKVtkdXJhdGlvbiA8IChjb3VudCoyMCkgKyA0MF0pDQpQU0YkbmFtZSA8LSAiRmlsdGVyZWQgUHJpbWFyeSBTY2hvb2wgQ29udGFjdHMiDQoNCiMgRXhwZWN0aW5nIDI0MiB2ZXJ0aWNlcyAyNzU5IGVkZ2VzDQpzdW1tYXJ5KFBTRikNCmBgYA0KDQpBIGZyZXF1ZW5jeSB0YWJsZSBvZiB1cGRhdGVkIGNvdW50cyBhbmQgZHVyYXRpb25zIGlzIHNob3duIGJlbG93LiANCg0KYGBge3J9DQp0YWJsZShjb3VudD1FKFBTRikkY291bnQsIGR1cmF0aW9uPUUoUFNGKSRkdXJhdGlvbilbMToxMCwxOjEyXQ0KYGBgIA0KDQoqKkFkZGluZyBHcmFkZSBBdHRyaWJ1dGUqKg0KDQpXZSB3b3VsZCBsaWtlIHRvIGFuYWx5emUgYnkgZ3JhZGUgbGV2ZWwsIGJ1dCBncmFkZSBpcyBjb2RlZCBvbmx5IGluZGlyZWN0bHkgYXMgY2xhc3NuYW1lLiBCZWxvdyB3ZSAgYSBuZXcgYXR0cmlidXRlIGNhbGxlZCAnZ3JhZGUnIGFuZCBnaXZlIGl0IGFwcHJvcHJpYXRlIHZhbHVlcyBieSBjb252ZXJzaW9uIG9mIHRoZSAnY2xhc3NuYW1lJyBhdHRyaWJ1dGUgYW5kIHByb3ZpZGUgYSBmcmVxdWVuY3kgdGFibGUgb2YgdGhlIG5ldyBncmFkZSBhdHRyaWJ1dGUuIA0KDQpgYGB7cn0NClYoUFNGKSRncmFkZSA8LSBzdWJzdHIoVihQU0YpJGNsYXNzbmFtZSwgMSwgMSkNCnRhYmxlKFYoUFNGKSRncmFkZSkNCmBgYA0KDQpOb3RpY2UgdGhhdCB1bmxpa2UgdGhlIHByZXZpb3VzIGFuYWx5c2lzIHRoZSBncmFkZSBhdHRyaWJ1dGUgaW5jbHVkZXMgIlQiIGZvciBUZWFjaGVyLCBhIG5vbi1udW1lcmljIHZhbHVlLiBUaGlzIHdpbGwgYWZmZWN0IGhvdyB3ZSBjb21wdXRlIGFzc29ydGF0aXZpdHkuIA0KDQoqKlNpbXBsaWZpbmcgQXR0cmlidXRlIExhYmVscyBmb3IgVmlzdWFsaXphdGlvbioqIA0KDQpXZSBzaG9ydGVuIHRoZXNlIHZlcnRleCBhdHRyaWJ1dGVzIHNvIHRoZXkgdGFrZSBsZXNzIHNwYWNlIHdoZW4gdmlzdWFsaXplZCwgY2hhbmdpbmcgXCRnZW5kZXIgIlVua25vd24iIHRvICJVIiBhbmQgXCRjbGFzc25hbWUgIlRlYWNoZXJzIiB0byAiVCIsIHJlc3VsdGluZyBpbiB0aGUgZm9sbG93aW5nIHNldHMgb2YgdmFsdWVzOiANCg0KYGBge3J9DQpWKFBTRikkZ2VuZGVyIDwtIHJlcGxhY2UoVihQU0YpJGdlbmRlciwgVihQU0YpJGdlbmRlcj09IlVua25vd24iLCAiVSIpDQpzb3J0KHVuaXF1ZShWKFBTRikkZ2VuZGVyKSkNClYoUFNGKSRjbGFzc25hbWUgPC0gcmVwbGFjZShWKFBTRikkY2xhc3NuYW1lLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBWKFBTRikkY2xhc3NuYW1lPT0iVGVhY2hlcnMiLCAiVCIpDQpzb3J0KHVuaXF1ZShWKFBTRikkY2xhc3NuYW1lKSkNCmBgYA0KDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCiMjIyMgMi4gQ29tcHV0aW5nIGFuZCBDb21wYXJpbmcgUGFydGl0aW9ucw0KDQpCZWxvdyB3ZSBjb21wdXRlIHBhcnRpdGlvbnMgdXNpbmcgdGhlIEluZm9NYXAgYW5kIExvdXZhaW4gY29tbXVuaXR5IGRldGVjdGlvbiBtZXRob2RzLCBhbmQgY29tcGFyZSB0aGVtIHRvIGVhY2ggb3RoZXIgYW5kIHR3byBub2RlIGF0dHJpYnV0ZXMgdGhhdCBtYXkgcHJlZGljdCBjb25uZWN0aXZpdHksIENsYXNzbmFtZSBhbmQgR3JhZGUuIEFsbCBvZiB0aGVzZSBwYXJ0aXRpb24gdGhlIG5ldHdvcmsuIFdlIGFzazogaG93IHdlbGwgZG9lcyBlYWNoIHBhcnRpdGlvbmluZyBjYXB0dXJlIHRoZSBjb25uZWN0aXZpdHkgb2YgdGhlIG5vZGVzPyBob3cgc2ltaWxhciBhcmUgdGhlIHBhcnRpdGlvbnMgdG8gZWFjaCBvdGhlcj8NCg0KIyMjIyMgKGEpIENvbW11bml0eSBEZXRlY3Rpb24gUGFydGl0aW9ucyANCg0KKipJbmZvTWFwKiogDQoNCkluIG9yZGVyIHRvIGFjY291bnQgZm9yIHRoZSB3aWRlIHZhcmlhdGlvbiBpbiBkdXJhdGlvbiBvZiBjb250YWN0cywgd2UgdXNlIGNvbnRhY3QgZHVyYXRpb24gYXMgZWRnZSB3ZWlnaHRzIGluIHRoaXMgYW5hbHlzaXMuIFRoZSByZXN1bHRpbmcgY29tbXVuaXR5IHNpemVzIGFyZSBkaXNwbGF5ZWQuICANCg0KYGBge3J9DQpQU0YuaW5mb21hcCA8LSBjbHVzdGVyX2luZm9tYXAoUFNGLCBlLndlaWdodHM9IEUoUFNGKSRkdXJhdGlvbikNCnNpemVzKFBTRi5pbmZvbWFwKQ0KYGBgDQoNCioqTG91dmFpbioqIA0KDQpBZ2Fpbiwgd2UgdXNlIGNvbnRhY3QgZHVyYXRpb24gYXMgZWRnZSB3ZWlnaHRzIGluIHRoaXMgYW5hbHlzaXMuIFRoZSByZXN1bHRpbmcgY29tbXVuaXR5IHNpemVzIGFyZSBkaXNwbGF5ZWQuIA0KDQpgYGB7cn0NClBTRi5sb3V2YWluIDwtIGNsdXN0ZXJfbG91dmFpbihQU0YsIHdlaWdodHMgPSBFKFBTRikkZHVyYXRpb24pDQpzaXplcyhQU0YubG91dmFpbikNCmBgYA0KDQojIyMjIyAoYikgQ29tcGFyaXNvbiBieSBNb2R1bGFyaXR5IGFuZCBBc3NvcnRhdGl2aXR5IA0KDQpUaGUgYXR0cmlidXRlIGJhc2VkIGFuZCBjb21wdXRlZCBwYXJ0aXRpb25zIGFyZSBjb21wYXJlZCBvbiB0aGVzZSBtZXRyaWNzOiANCg0KYGBge3J9DQojIFJlbWluZGVyOiB1bmxpa2UgQW5hbHlzaXMgNiwgZ3JhZGUgbm93IGluY2x1ZGVzICJUIiAgDQogcmJpbmQoDQogICB0aWJibGUobWV0cmljID0gIk1vZHVsYXJpdHkiLA0KICAgICAgICAgIENsYXNzbmFtZSA9IG1vZHVsYXJpdHkoUFNGLCBhcy5pbnRlZ2VyKGFzLmZhY3RvcihWKFBTRikkY2xhc3NuYW1lKSkpLA0KICAgICAgICAgIEdyYWRlICAgICA9IG1vZHVsYXJpdHkoUFNGLCBhcy5pbnRlZ2VyKGFzLmZhY3RvcihWKFBTRikkZ3JhZGUpKSksDQogICAgICAgICAgTG91dmFpbiAgID0gbW9kdWxhcml0eShQU0YubG91dmFpbiksDQogICAgICAgICAgSW5mb01hcCAgID0gbW9kdWxhcml0eShQU0YuaW5mb21hcCksDQogICApLA0KICAgICAgICAgIA0KICAgdGliYmxlKG1ldHJpYyA9ICJBc3NvcnRhdGl2aXR5IiwNCiAgICAgICAgICBDbGFzc25hbWUgPSBhc3NvcnRhdGl2aXR5X25vbWluYWwoUFNGLCBhcy5pbnRlZ2VyKGFzLmZhY3RvcihWKFBTRikkY2xhc3NuYW1lKSkpLA0KICAgICAgICAgIEdyYWRlICAgICA9IGFzc29ydGF0aXZpdHlfbm9taW5hbChQU0YsIGFzLmludGVnZXIoYXMuZmFjdG9yKFYoUFNGKSRncmFkZSkpKSwNCiAgICAgICAgICBMb3V2YWluICAgPSBhc3NvcnRhdGl2aXR5KFBTRiwgbWVtYmVyc2hpcChQU0YubG91dmFpbikpLA0KICAgICAgICAgIEluZm9NYXAgICA9IGFzc29ydGF0aXZpdHkoUFNGLCBtZW1iZXJzaGlwKFBTRi5pbmZvbWFwKSkNCiAgICkNCiApDQpgYGANCg0KKipFeHBsYW5hdGlvbiBvZiBSYW5rIE9yZGVyaW5nIG9mIE1ldHJpY3MqKg0KDQpBc3NvcnRhdGl2aXR5IGlzIG1vZHVsYXJpdHkgc2NhbGVkIHN1Y2ggdGhhdCAxIGlzIHRoZSBtYXhpbXVtIHZhbHVlIGl0IGNhbiBoYXZlLiBXZSBtaWdodCBleHBlY3QgdGhhdCB0aGlzIG1lYW5zIHRoYXQgYXNzb3J0YXRpdml0eSBpcyBhbHdheXMgbGFyZ2VyLCB5ZXQgd2Ugc2VlIHRoYXQgdGhpcyBpcyBub3QgdGhlIGNhc2UgZm9yIExvdXZhaW4gYW5kIEluZm9NYXAuDQoNClRoaXMgd291bGQgaW5kaWNhdGUgdGhhdCBtb2R1bGFyaXR5IG9uIExvdXZhaW4gYW5kIEluZm9NYXAgYXJlIHJldHVybmluZyB0aGF0IHRoZXJlIGFyZSBzbGlnaHRseSBtb3JlIGNvbW11bml0aWVzIGRldGVjdGVkIHRoYW4gaG93IHdlbGwgTG91dmFpbiBhbmQgSW5mb01hcCBhcmUgaW4gYXNzb3J0YXRpdmVuZXNzLiBNYXliZSBpdCBpcyBiZWNhdXNlIHdlJ3JlIGFwcGx5aW5nIGFzc29ydGF0aXZpdHkgb24gdGhlIHNwZWNpZmljIGNvbW11bml0aWVzIG9mIFBTRi5sb3V2YWluIG9yIFBTRi5pbmZvbWFwLiBNb2R1bGFyaXR5IG1lYXN1cmVzIGhvdyBzZXBhcmF0ZWQgYXJlIHRoZSBkaWZmZXJlbnQgdmVydGV4IHR5cGVzIGZyb20gZWFjaCBvdGhlciBzbyBhc3N1bWluZyBteSBudW1iZXJzIGFyZSBjb3JyZWN0LCB0aGUgYW1vdW50IG9mIGNvbW11bml0aWVzIHRoYXQgYXJlIHByZXNlbnQgaXMgbW9yZSB0aGFuIHRoZSBhbW91bnQgb2YgY29ubmVjdGVkIHZlcnRpY2VzIHRoYXQgaGF2ZSB0aGUgc2FtZSBsYWJlbHMgb3Igc2ltaWxhciBhc3NpZ25lZCB2YWx1ZXMuIE9yIHBlcmhhcHMgaXQgaXMgYmVjYXVzZSB3ZSBjb25zaWRlcmVkIHRoZSB3ZWlnaHRzIGZvciBib3RoIExvdXZhaW4gYW5kIEluZm9tYXAgdG8gYmUgYmFzZWQgb24gZHVyYXRpb24uIEFsdGhvdWdoIHRoZXJlIGlzbid0IGEgbG90IG9mIGNvbm5lY3Rpb25zLCB0aGUgd2VpZ2h0cyBvZiBkdXJhdGlvbiBmb3IgdGhlc2UgY29ubmVjdGlvbnMgYXJlIGZpbmRpbmcgbW9yZSBjb21tdW5pdGllcyB0aGFuIHVzdWFsIHRocm91Z2ggbW9kdWxhcml0eSBvcHRpbWl6YXRpb24gYW5kIGZsb3cgb3B0aW1pemF0aW9uLiANCg0KRnJvbSB0aGUgcHJldmlvdXMgYXNzaWdubWVudCwgSSByZW1lbWJlciB0aGF0IFBTRiBoYWQgZGlmZmVyZW50IGdyYWRlIGxldmVscyBzbyBiYXNlZCBvbiB0aGUgaW5mb3JtYXRpb24gYWJvdmUsIG1vc3Qgc3R1ZGVudHMgYXJlIGluIGNvbW11bml0aWVzIChpLmUuLCBncmFkZSksIGJ1dCB0aGV5IGRvbid0IHRhbGsgdG8gb3RoZXIgc3R1ZGVudHMgaW4gb3RoZXIgZ3JhZGVzIGFzIG11Y2gsIGFuZCB0aGV5IHByb2JhYmx5IGRvbid0IHRhbGsgdG8gZXZlcnlvbmUgaW4gdGhlaXIgb3duIGdyYWRlIGVpdGhlci4gVGhpcyBjb3VsZCBwb3NzaWJseSBleHBsYWluIHRoZSBwcmV2aW91cyBxdWVzdGlvbiBvbiB3aHkgYXNzb3J0YXRpdml0eSBpcyBsb3dlci4gKEkgdXNlIHRoaXMgcmVhc29uaW5nIGZvciB0aGUgcXVlc3Rpb24gYmVsb3cgYXMgd2VsbCkuDQoNCioqSG93IFdlbGwgUGFydGl0aW9ucyBSZWZsZWN0IE5ldHdvcmsgQ29ubmVjdGl2aXR5KiogDQoNClNldHRpbmcgdGhlc2UgZGlmZmVyZW5jZXMgYXNpZGUsIHRoZXNlIG1ldHJpY3MgaW5kaWNhdGUgaG93IHdlbGwgZWFjaCBwYXJ0aXRpb24gcmVmbGVjdHMgdGhlIGNvbm5lY3Rpdml0eSBvZiB0aGUgbmV0d29yayBhcyBmb2xsb3dzLiANCg0KTW9kdWxhcml0eSBpbmRpY2F0ZXMgdGhhdCBtYWpvcml0eSBvZiB0aGUgbm9kZXMgaW4gUFNGIGJlbG9uZyB0byBhIGNvbW11bml0eSBpZiBMb3V2YWluIGFuZCBJbmZvTWFwIHJldHVybmVkIDAuNzAuIFlvdSB3b3VsZCBhc3N1bWUgdGhlbiB0aGVyZSB3b3VsZCBiZSBhIGxvdCBvZiBub2RlcyBjb25uZWN0ZWQgdG8gZWFjaCBvdGhlciBidXQgdGhhdCBpc24ndCB0aGUgY2FzZS4gQXNzb3J0YXRpdml0eSBpbmRpY2F0ZXMgdGhhdCBhbHRob3VnaCBtYWpvcml0eSBvZiB0aGUgbm9kZXMgYXJlIGluIGNvbW11bml0aWVzLCB0aGUgZGVncmVlIG9mIGNvcnJlbGF0aW9uIGJldHdlZW4gY29ubmVjdGVkIG5vZGVzIGlzIGxvd2VyIHRoYW4gdGhlIGFtb3VudCBvZiBjb21tdW5pdGllcyB0aGVyZSBhcmUuIE9yIGluIG90aGVyIHdvcmRzLCB0aGUgcHJlZmVyZW5jZSBmb3IgYSBuZXR3b3JrJ3Mgbm9kZXMgdG8gYXR0YWNoIHRvIG90aGVycyB0aGF0IGFyZSBzaW1pbGFyIGlzIGxvd2VyIHRoYW4gdGhlIGFtb3VudCBvZiBjb21tdW5pdGllcyBwcmVzZW50LiANCg0KSSBhc3N1bWUgdGhpcyBtZWFucyB0aGF0IHRoZSBuZXR3b3JrIGRvZXMgbm90IGhhdmUgbWFueSBub2RlcyBjcm9zc2luZyBvdmVyIHRvIG90aGVyIGNvbW11bml0aWVzIGJ1dCByYXRoZXIgc3RheXMgd2l0aGluIHRoZWlyIG93biBjb21tdW5pdGllczsgYW5kIGV2ZW4gdGhlbiwgdGhlIG5vZGVzIHByb2JhYmx5IGRvbid0IHRhbGsgYXMgbXVjaCB0byBvdGhlciBub2RlcyB3aXRoaW4gdGhlaXIgb3duIGNvbW11bml0aWVzLiBSZWFzb25pbmcgYmFzZWQgb24gcHJldmlvdXMgcXVlc3Rpb24gYWJvdmUuIA0KDQpGcm9tIHRoZSBwcmV2aW91cyBhc3NpZ25tZW50LCBJIHJlbWVtYmVyIHRoYXQgUFNGIGhhZCBkaWZmZXJlbnQgZ3JhZGUgbGV2ZWxzIHNvIGJhc2VkIG9uIHRoZSBpbmZvcm1hdGlvbiBhYm92ZSwgbW9zdCBzdHVkZW50cyBhcmUgaW4gY29tbXVuaXRpZXMgKGkuZS4sIGdyYWRlKSwgYnV0IHRoZXkgZG9uJ3QgdGFsayB0byBvdGhlciBzdHVkZW50cyBpbiBvdGhlciBncmFkZXMgYXMgbXVjaCwgYW5kIHRoZXkgcHJvYmFibHkgZG9uJ3QgdGFsayB0byBldmVyeW9uZSBpbiB0aGVpciBvd24gZ3JhZGUgZWl0aGVyLiBUaGlzIGNvdWxkIHBvc3NpYmx5IGV4cGxhaW4gdGhlIHByZXZpb3VzIHF1ZXN0aW9uIG9uIHdoeSBhc3NvcnRhdGl2aXR5IGlzIGxvd2VyLg0KDQpCdXQgdGhpcyBsZWF2ZXMgb3BlbiB0aGUgcXVlc3Rpb24gb2YgaG93IHRoZXNlIHBhcnRpdGlvbnMgY29tcGFyZSB0byBlYWNoIG90aGVyLiANCg0KIyMjIyMgKGMpIENvbXBhcmlzb24gYnkgTm9ybWFsaXplZCBNdXR1YWwgSW5mb3JtYXRpb24gDQoNCk5vcm1hbGl6ZWQgTXV0dWFsIEluZm9ybWF0aW9uIHRlbGxzIHVzIGhvdyBtdWNoIGluZm9ybWF0aW9uIGEgcGFpciBvZiBwYXJ0aXRpb25pbmcgKGludGVycHJldGVkIGFzIHJhbmRvbSB2YXJpYWJsZXMpIHNoYXJlIHdpdGggZWFjaCBvdGhlci4gSXQgaXMgIG5vcm1hbGl6ZWQgdG8gWzAsMV0sIG1ha2luZyBpdCBsaWtlIGEgY29ycmVsYXRpb24gY29lZmZpY2llbnQuIChodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9NdXR1YWxfaW5mb3JtYXRpb24pIA0KDQoNCmBgYHtyfQ0KDQojIFVzaW5nIGFueSBhcHByb2FjaCB5b3UgcHJlZmVyLCBtYWtlIGEgY29ycmVsYXRpb24gbWF0cml4IG9mIHRoaXMgZm9ybToNCiMgcGFydGl0aW9uICBDbGFzc25hbWUgIEdyYWRlICAgICAgSW5mb01hcCAgICBMb3V2YWluIA0KIyBDbGFzc25hbWUgIHgueHh4eHggICAgeC54eHh4eCAgICB4Lnh4eHh4ICAgIHgueHh4eHgNCiMgR3JhZGUgICAgICB4Lnh4eHh4ICAgIHgueHh4eHggICAgeC54eHh4eCAgICB4Lnh4eHh4DQojIEluZm9NYXAgICAgeC54eHh4eCAgICB4Lnh4eHh4ICAgIHgueHh4eHggICAgeC54eHh4eA0KIyBMb3V2YWluICAgIHgueHh4eHggICAgeC54eHh4eCAgICB4Lnh4eHh4ICAgIHgueHh4eHgNCg0KIyBJIGVuZGVkIHVwIHVzaW5nIGEgY29udmVudGlvbmFsIHByb2dyYW1taW5nIGZvci1sb29wIGFwcHJvYWNoLiBUaGVyZQ0KIyBpcyBwcm9iYWJseSBhbiBlbGVnYW50IFItc3R5bGUgYXBwcm9hY2gsIGJ1dCB0aGUgdGliYmxlLWJhc2VkDQojIHNvbHV0aW9uIEkgY29uc3RydWN0ZWQgcmVxdWlyZWQgcmVwZWF0aW5nIGNvZGUgdGhhdCBjb25zdHJ1Y3RzDQojIG1lbWJlcnNoaXAgbGlzdHMsIHdoaWNoIGRpZCBub3Qgc2VlbSBhbnkgbW9yZSBlbGVnYW50IHRoYW4gYSBsb29wLg0KDQoNCnJiaW5kKA0KICAgdGliYmxlKHBhcml0aW9uID0gIkNsYXNzbmFtZSIsDQogICAgICAgICAgQ2xhc3NuYW1lID0gY29tcGFyZShWKFBTRikkY2xhc3NuYW1lLCBWKFBTRikkY2xhc3NuYW1lLCBtZXRob2QgPSAibm1pIiksDQogICAgICAgICAgR3JhZGUgICAgID0gY29tcGFyZShWKFBTRikkY2xhc3NuYW1lLCBWKFBTRikkZ3JhZGUsIG1ldGhvZD0ibm1pIiksDQogICAgICAgICAgTG91dmFpbiAgID0gY29tcGFyZShWKFBTRikkY2xhc3NuYW1lLCBtZW1iZXJzaGlwKFBTRi5sb3V2YWluKSwgbWV0aG9kPSJubWkiKSwNCiAgICAgICAgICBJbmZvTWFwICAgPSBjb21wYXJlKFYoUFNGKSRjbGFzc25hbWUsIG1lbWJlcnNoaXAoUFNGLmluZm9tYXApLCBtZXRob2Q9Im5taSIpLA0KICAgKSwNCiAgICAgICAgICANCiAgIHRpYmJsZShwYXJpdGlvbiA9ICJHcmFkZSIsDQogICAgICAgICAgQ2xhc3NuYW1lID0gY29tcGFyZShWKFBTRikkZ3JhZGUsIFYoUFNGKSRjbGFzc25hbWUsIG1ldGhvZCA9ICJubWkiKSwNCiAgICAgICAgICBHcmFkZSAgICAgPSBjb21wYXJlKFYoUFNGKSRncmFkZSwgVihQU0YpJGdyYWRlLCBtZXRob2Q9Im5taSIpLA0KICAgICAgICAgIExvdXZhaW4gICA9IGNvbXBhcmUoVihQU0YpJGdyYWRlLCBtZW1iZXJzaGlwKFBTRi5sb3V2YWluKSwgbWV0aG9kPSJubWkiKSwNCiAgICAgICAgICBJbmZvTWFwICAgPSBjb21wYXJlKFYoUFNGKSRncmFkZSwgbWVtYmVyc2hpcChQU0YuaW5mb21hcCksIG1ldGhvZD0ibm1pIiksDQogICApLA0KICAgDQogICB0aWJibGUocGFyaXRpb24gPSAiTG91dmFpbiIsDQogICAgICAgICAgQ2xhc3NuYW1lID0gY29tcGFyZShtZW1iZXJzaGlwKFBTRi5sb3V2YWluKSwgVihQU0YpJGNsYXNzbmFtZSwgbWV0aG9kID0gIm5taSIpLA0KICAgICAgICAgIEdyYWRlICAgICA9IGNvbXBhcmUobWVtYmVyc2hpcChQU0YubG91dmFpbiksIFYoUFNGKSRncmFkZSwgbWV0aG9kPSJubWkiKSwNCiAgICAgICAgICBMb3V2YWluICAgPSBjb21wYXJlKG1lbWJlcnNoaXAoUFNGLmxvdXZhaW4pLCBtZW1iZXJzaGlwKFBTRi5sb3V2YWluKSwgbWV0aG9kPSJubWkiKSwNCiAgICAgICAgICBJbmZvTWFwICAgPSBjb21wYXJlKG1lbWJlcnNoaXAoUFNGLmxvdXZhaW4pLCBtZW1iZXJzaGlwKFBTRi5pbmZvbWFwKSwgbWV0aG9kPSJubWkiKSwNCiAgICksDQogICANCiAgIHRpYmJsZShwYXJpdGlvbiA9ICJJbmZvbWFwIiwNCiAgICAgICAgICBDbGFzc25hbWUgPSBjb21wYXJlKG1lbWJlcnNoaXAoUFNGLmluZm9tYXApLCBWKFBTRikkY2xhc3NuYW1lLCBtZXRob2QgPSAibm1pIiksDQogICAgICAgICAgR3JhZGUgICAgID0gY29tcGFyZShtZW1iZXJzaGlwKFBTRi5pbmZvbWFwKSwgVihQU0YpJGdyYWRlLCBtZXRob2Q9Im5taSIpLA0KICAgICAgICAgIExvdXZhaW4gICA9IGNvbXBhcmUobWVtYmVyc2hpcChQU0YuaW5mb21hcCksIG1lbWJlcnNoaXAoUFNGLmxvdXZhaW4pLCBtZXRob2Q9Im5taSIpLA0KICAgICAgICAgIEluZm9NYXAgICA9IGNvbXBhcmUobWVtYmVyc2hpcChQU0YuaW5mb21hcCksIG1lbWJlcnNoaXAoUFNGLmluZm9tYXApLCBtZXRob2Q9Im5taSIpLA0KICAgKQ0KICkNCmBgYA0KDQpCZWNhdXNlIHRoZSB0YWJsZSBhYm92ZSBlc3NlbnRpYWxseSByZXByZXNlbnRzIGEgbXVsdGlwbGljYXRpb24gbWF0cml4IHlvdSdyZSBnb2luZyB0byBzZWUgcmVwZWF0aW5nIHZhbHVlcyBmb3IgdGhlIHRoZSBzYW1lICh4LHkpIGFuZCAoeSx4KS4gSG93ZXZlciwgaWYgd2UgaWdub3JlIHRoYXQgZm9yIGEgc2Vjb25kLCBjb25zaWRlciB0aGUgdGhlIGhpZ2hlc3QgdmFsdWVzIGZyb20gb3VyIGNvbXBhcmlzb24gdGFibGUuIEluZm9tYXAgYW5kIGNsYXNzbmFtZSBzdXJwcmlzaW5nbHkgZG9lcyB3ZWxsIGFzIHRoZSBoaWdoZXN0IGRpc3RhbmNlIGJldHdlZW4gdGhlIHR3byBjb21tdW5pdHkgc3RydWN0dXJlcyBhdCAwLjkzIGJ1dCBub3QgZ3JhZGUgd2hpY2ggaXMgdGhlIGxvd2VzdCBvdXQgb2YgYWxsIGNvbXBhcmlzb25zIGF0IDAuNzYuIFRoZSBpbnZlcnNlIGlzIHNvbWV3aGF0IHRydWUgZm9yIGxvdXZhaW4uIExvdXZhaW4gYW5kIGNsYXNzbmFtZSBpcyByZWxhdGl2ZWx5IGxvdyBhdCAwLjc5IHdoaWxzdCBsb3V2YWluIGFuZCBncmFkZSBpcyByZWxhdGl2ZWx5IG1pZCBhdCAwLjg3LiANCg0KUGVyaGFwcyB3ZSBjYW4gY29uc2lkZXIgdGhlIHJlbGF0aW9uc2hpcCB0aGF0IGxvdXZhaW4gaXMgdG8gY2xhc3NuYW1lIGFzIGluZm9tYXAgaXMgdG8gZ3JhZGUuIExvdXZhaW4gYW5kIGNsYXNzbmFtZSBoYXMgbG93IGNvcnJlbGF0aW9uIGJlY2F1c2UgbG91dmFpbiBpcyBjb25zaWRlcmVkIG1vcmUgZ2VuZXJpYyB3aGlsc3QgaW5mb21hcCBhbmQgZ3JhZGUgaGFzIGxlc3MgY29ycmVsYXRpb24gYmVjYXVzZSBpbmZvbWFwIGlzIGNvbnNpZGVyZWQgbW9yZSAiZ3JhbnVsYXIiIGFuZCBwaWNrcyBvdXQgaW5kaXZpZHVhbCBjbGFzc25hbWVzIGJldHRlci4gDQoNCl9fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fXw0KIyMjIyAzLiBFeGFtaW5pbmcgUmVzdWx0cyBpbiBHZXBoaQ0KDQpWaXN1YWxpemF0aW9ucyBpbiBHZXBoaSB3aWxsIGJlIHVzZWQgdG8gaW50ZXJwcmV0IHRoZSBwYXJ0aXRpb25zLg0KDQojIyMjIyAoYSkgRXhwb3J0aW5nIFJlc3VsdHMgdG8gR2VwaGkgDQoNCkNvbW11bml0eSBtZW1iZXJzaGlwIGlzIGFzc2lnbmVkIHRvIHZlcnRpY2VzIHVuZGVyIGF0dHJpYnV0ZXMgJGxvdXZhaW4gYW5kICRpbmZvbWFwLg0KDQpgYGB7cn0NCiBWKFBTRikkbG91dmFpbiA8LSBtZW1iZXJzaGlwKFBTRi5sb3V2YWluKQ0KIFYoUFNGKSRpbmZvbWFwIDwtIG1lbWJlcnNoaXAoUFNGLmluZm9tYXApDQpgYGANCg0KSW4gR2VwaGksIHdlIHdhbnQgdG8gdmlzdWFsaXplIGVkZ2VzIHdlaWdodGVkIGJ5IGVkZ2UgYXR0cmlidXRlICdkdXJhdGlvbicuIEJ1dCBHZXBoaSBkb2VzIG5vdCBsZXQgdXMgc3BlY2lmeSB0aGUgbG9jYXRpb24gb2YgdGhlIHdlaWdodHMsIGFuZCBhbHdheXMgdXNlcyB0aGUgJ3dlaWdodCcgYXR0cmlidXRlLiBTbywgd2Ugd2FudCB0byB3cml0ZSBkdXJhdGlvbiBpbnRvIHRoZSB3ZWlnaHQgYXR0cmlidXRlLiBIb3dldmVyLCBpbnNwZWN0aW9uIHJldmVhbHMgdGhhdCB0aGVyZSBhcmUgdHdvIHZhbHVlczogMSBhbmQgMi4gVGhlc2UgY29tZSBmcm9tIGNvbGxhcHNpbmcgdGhlIG11bHRpZ3JhcGgsIGFuZCBpbmRpY2F0ZSB0aGUgbnVtYmVyIG9mIGRheXMgb24gd2hpY2ggdHdvIHN0dWRlbnRzIGhhZCBjb250YWN0LiBXZSdsbCBmaXJzdCBwcmVzZXJ2ZSB0aGlzIGluZm9ybWF0aW9uIGluIGNhc2UgaXQgaXMgdXNlZnVsIGluICdkYXlzJy4gDQoNCmBgYHtyfQ0Kc29ydCh1bmlxdWUoRShQU0YpJHdlaWdodCkpDQogRShQU0YpJGRheXMgPC0gRShQU0YpJHdlaWdodA0KIEUoUFNGKSR3ZWlnaHQgPC0gRShQU0YpJGR1cmF0aW9uDQpzdW1tYXJ5KFBTRikNCmBgYA0KDQpUaGVuIHdlIHdyaXRlIG91dCBhIGdyYXBobWwgZmlsZSBmb3IgaW5zcGVjdGlvbiBpbiBHZXBoaS4NCg0KYGBge3J9DQp3cml0ZV9ncmFwaChQU0YsICJOZXR3b3Jrcy9QcmltYXJ5LVNjaG9vbC1TdHVkZW50cy1GaWx0ZXJlZC5ncmFwaG1sIiwgZm9ybWF0PSJncmFwaG1sIikNCmBgYA0KDQojIyMjIyAoYikgU3BhdGlhbGl6ZWQgVmlzdWFsaXphdGlvbiBpbiBHZXBoaSANCg0KQSBzcGF0aWFsaXplZCB2aXN1YWxpemF0aW9uIG9mIHRoZSBuZXR3b3JrIHdhcyBjb25zdHJ1Y3RlZCBpbiBHZXBoaSB1c2luZyBGb3JjZSBBdGxhcyAyIGFuZCB0aGUgZm9sbG93aW5nIHBhcmFtZXRlcnM6IA0KDQoqIE5vZGVzIHNpemVkIGJ5IGRlZ3JlZSBhbmQgbGFiZWxlZCB3aXRoIHRoZWlyIGNsYXNzbmFtZSBhbmQgZ2VuZGVyLiANCiogTGluLUxvZyBtb2RlIA0KKiBQcmV2ZW50IE92ZXJsYXAgZmlsdGVyIA0KKiBFZGdlIFdlaWdodCBJbmZsdWVuY2Ugc2V0IHRvIDAgKG90aGVyd2lzZSB0aGUgbGFyZ2UgZHVyYXRpb24gd2VpZ2h0cyB3aWxsIGNvbXByZXNzIHRoZSBsYXlvdXQpDQoqIEdyYXZpdHkgMi4wIHRvIGdldCBhIGNvbXBhY3QgYnV0IG5vdCBjcm93ZGVkIHZpc3VhbGl6YXRpb24uIA0KDQpOb2RlcyB3ZXJlIGxhYmVsZWQgd2l0aCBjbGFzc25hbWUgYW5kIGdlbmRlci4gUGxlYXNlIHNlZSB0aGUgZW5jbG9zZWQgR2VwaGkgcHJvamVjdCBQcmltYXJ5LVNjaG9vbC1Db21tdW5pdGllcy5nZXBoaSBmb3IgaGlnaCByZXNvbHV0aW9uIGltYWdlcy4gUmVzdWx0cyBhcmUgaWxsdXN0cmF0ZWQgaW4gdGhlIGZvbGxvd2luZyBzY3JlZW4gY2FwdHVyZXMuIA0KDQojIyMjIyAoYykgVmlzdWFsaXphdGlvbiBvZiBQYXJ0aXRpb25zIA0KDQpCZWxvdyB3ZSB2aXN1YWxpemUgcGFydGl0aW9uaW5nIGJ5IGNsYXNzbmFtZSwgZ3JhZGUsIEluZm9NYXAsIGFuZCBMb3V2YWluIGJ5IGNvbG9yaW5nIHRoZSBhYm92ZSBzcGF0aWFsaXplZCB2aXN1YWxpemF0aW9uIGJ5IHRoZXNlIHBhcnRpdGlvbnMuIENvbG9yIGtleXMgYXJlIHByb3ZpZGVkLiBXZSBvcmdhbml6ZSB0aGUgcmVzdWx0cyB0byBoaWdobGlnaHQgc2ltaWxhcml0aWVzLCBidXQgbGVhdmUgdGhlIGRpc2N1c3Npb24gZm9yIHRoZSBuZXh0IHNlY3Rpb24uIA0KDQoqKlBhcnRpdGlvbiBieSBDbGFzc25hbWUqKiANCg0KYGBge3IgIGVjaG89RkFMU0UsIGZpZy5hbGlnbj0iY2VudGVyIiwgZmlnLmNhcCA9ICJQYXJ0aXRpb24gYnkgQ2xhc3NuYW1lIn0NCiBpbmNsdWRlX2dyYXBoaWNzKCJJbWFnZXMvY2xhc3NuYW1lLnBuZyIsIGRwaT0xNTApDQpgYGANCg0KYGBge3IgIGVjaG89RkFMU0UsIGZpZy5hbGlnbj0iY2VudGVyIiwgZmlnLmNhcCA9ICJDbGFzc25hbWUgQ29sb3IgS2V5In0NCiMgUGxlYXNlIGluY2x1ZGUgYSBjb2xvciBrZXkgZnJvbSBHZXBoaSBoZXJlIA0KIGluY2x1ZGVfZ3JhcGhpY3MoIkltYWdlcy9jbGFzc25hbWVfa2V5LnBuZyIpDQpgYGANCg0KKipQYXJ0aXRpb24gYnkgR3JhZGUqKiANCg0KYGBge3IgIGVjaG89RkFMU0UsIGZpZy5hbGlnbj0iY2VudGVyIiwgZmlnLmNhcCA9ICJQYXJ0aXRpb24gYnkgR3JhZGUifQ0KIGluY2x1ZGVfZ3JhcGhpY3MoIkltYWdlcy9ncmFkZS5wbmciLCBkcGk9MTUwKQ0KYGBgDQoNCmBgYHtyICBlY2hvPUZBTFNFLCBmaWcuYWxpZ249ImNlbnRlciIsIGZpZy5jYXAgPSAiR3JhZGUgQ29sb3IgS2V5In0NCiMgUGxlYXNlIGluY2x1ZGUgYSBjb2xvciBrZXkgZnJvbSBHZXBoaSBoZXJlDQogaW5jbHVkZV9ncmFwaGljcygiSW1hZ2VzL2dyYWRlX2tleS5wbmciKQ0KYGBgDQoNCioqUGFydGl0aW9uIGJ5IGluZm9tYXAqKiANCg0KYGBge3IgIGVjaG89RkFMU0UsIGZpZy5hbGlnbj0iY2VudGVyIiwgZmlnLmNhcCA9ICJQYXJ0aXRpb24gYnkgaW5mb21hcCJ9DQogaW5jbHVkZV9ncmFwaGljcygiSW1hZ2VzL2luZm9tYXAucG5nIiwgZHBpPTE1MCkNCmBgYA0KDQpgYGB7ciAgZWNobz1GQUxTRSwgZmlnLmFsaWduPSJjZW50ZXIiLCBmaWcuY2FwID0gImluZm9tYXAgQ29sb3IgS2V5In0NCiMgUGxlYXNlIGluY2x1ZGUgYSBjb2xvciBrZXkgZnJvbSBHZXBoaSBoZXJlIA0KIGluY2x1ZGVfZ3JhcGhpY3MoIkltYWdlcy9pbmZvbWFwX2tleS5wbmciKQ0KYGBgDQoNCioqUGFydGl0aW9uIGJ5IGxvdXZhaW4qKiANCg0KYGBge3IgIGVjaG89RkFMU0UsIGZpZy5hbGlnbj0iY2VudGVyIiwgZmlnLmNhcCA9ICJsb3V2YWluIFBhcnRpdGlvbiJ9DQogaW5jbHVkZV9ncmFwaGljcygiSW1hZ2VzL2xvdXZhaW4ucG5nIiwgZHBpPTE1MCkNCmBgYA0KDQpgYGB7ciAgZWNobz1GQUxTRSwgZmlnLmFsaWduPSJjZW50ZXIiLCBmaWcuY2FwID0gImxvdXZhaW4gQ29sb3IgS2V5In0NCiBpbmNsdWRlX2dyYXBoaWNzKCJJbWFnZXMvbG91dmFpbl9rZXkucG5nIikNCmBgYA0KDQojIyMjIyAoZCkgRGlzY3Vzc2lvbjogQ29tcGFyaXNvbiBvZiBQYXJ0aXRpb25zIA0KDQpXZSBkaXNjdXNzIHRocmVlIGNvbXBhcmlzb25zOiANCg0KKipDb21wYXJpbmcgQ29tbXVuaXR5IERldGVjdGlvbiBNZXRob2RzIHRvIEVhY2gtb3RoZXIqKg0KDQpXaGVuIHdlIGxvb2sgYXQgdGhlIHZpc3VsaXphdGlvbnMgYmV0d2VlbiBMb3V2YWluIGFuZCBJbmZvbWFwIHRoZSBvYnZpb3VzIGRpZmZlcmVuY2UgaXMgdGhhdCBsb3V2YWluIHJldHVybmVkIHRoYXQgNiBjb21tdW5pdGllcyB3ZXJlIGRldGVjdGVkIHdoaWxzdCBpbmZvbWFwIHJldHVybmVkIHRoYXQgMTAgY29tbXVuaXRpZXMgdGhhdCB3ZXJlIGRldGVjdGVkLiBQcm9iYWJseSBiZWNhdXNlIGluZm9tYXAgaXMgYmV0dGVyIGF0IGRldGVjdGluZyB0aGF0IGNlcnRhaW4gc3R1ZGVudHMgcHJlZmVyIHRvIHRhbGsgdG8gYSBtZW1iZXJzIG9mIHRoZSBzYW1lIHNwZWNpZmljIGdyYWRlICgyQSwgMkIpIGJ1dCBsb3V2YWluIGlzIGRldGVjdGluZyB0aGF0IHRoZXJlIGFyZSBlbm91Z2ggaW50ZXJhY3Rpb25zIGJldHdlZW4gc3R1ZGVudHMgb2YgdGhlIHNhbWUgZ3JhZGUgdGhhdCBpdCBjb25zaWRlcnMgYWxsIG9mIHRoZW0gdG8gYmUgd2l0aGluIHRoZSBzYW1lIGNvbW11bml0eSB3aXRoIGFuIGV4Y2VwdGlvbiBmb3IgZ3JhZGUgMSB3aGVyZSBpdCBzdWNjZXNzZnVsbHkgZGV0ZWN0ZWQgdGhhdCAxQSAoMS4wKSBhbmQgMUIgKDQuMCkgYXJlIHRlY2huaWNhbGx5IHNlcGFyYXRlIGNvbW11bml0aWVzLiBUaGlzIGlzbid0IGVudGlyZWx5IHdyb25nIGJ1dCBJIGd1ZXNzIHlvdSBjb3VsZCBpbnRlcnByZXQgdGhhdCBhcywgImxlc3MgYWNjdXJhdGUuIg0KDQoqKkNvbXBhcmluZyBDb21tdW5pdHkgRGV0ZWN0aW9uIE1ldGhvZHMgdG8gQ2xhc3NuYW1lIGFuZCBHcmFkZSoqDQoNCldoZW4gd2UgY29uc2lkZXIgdGhlIHZpc3VhbGl6YXRpb25zIGJldHdlZW4gdGhlIGNvbW11bml0eSBkZXRlY3Rpb24gbWV0aG9kcyB0byBjbGFzc25hbWUgYW5kIGdyYWRlIHdlIHNlZSB0aGF0IG15IGFzc3VtcHRpb25zIGZyb20gdGhlIHByZXZpb3VzIHF1ZXN0aW9uIGlzIGNvcnJlY3QuIEluZm9tYXAgZG9lcyBhIGdvb2Qgam9iIGRldGVjdGluZyB0aGF0IGFsdGhvdWdoIHRoZXJlIGFyZSA1IGdyYWRlIGxldmVscywgdGhlcmUgaXMgYWxzbyBhIHN1YiBkaXZpc2lvbiBiZXR3ZWVuIGdyYWRlIFhBIGFuZCBYQiB3aGVyZSB5b3UgY2FuIGNvbnNpZGVyIHRoaXMgYW5vdGhlciBzZXQgb2YgY29tbXVuaXRpZXMuIExvdXZhaW4gb25seSBkZXRlY3RlZCB0aGlzIHdpdGggZ3JhZGUgMSB3aGVyZSBpdCBkZXRlY3RlZCBhIGRpZmZlcmVuY2UgaW4gY29tbXVuaXR5IGJldHdlZW4gMUEgKDEuMCksIGFuZCAxQiAoNC4wKS4gDQoNCiMjIyMjIChlKSBPYnNlcnZhdGlvbnMgYWJvdXQgQWN0b3IgQmVoYXZpb3INCg0KQmFzZWQgb24gYWxsIG9mIHRoZSBhYm92ZSBhbmFseXNlcywgd2UgY2FuIGRyYXcgdGhlc2UgY29uY2x1c2lvbnMgYWJvdXQgc3R1ZGVudCBhbmQgdGVhY2hlciBiZWhhdmlvcjogDQoNCioqT2JzZXJ2YXRpb25zIGFib3V0IENvbGxlY3RpdmUgQmVoYXZpb3IqKiANCg0KSW50ZXJlc3RpbmdseSwgaWYgeW91IGNvbnNpZGVyIHRoZSBub2RlIHNpemVzIGJldHdlZW4gc3R1ZGVudHMgYW5kIHRlYWNoZXJzLCB0ZWFjaGVycyBhcmUgdmlzdWFsbHkgc21hbGxlciBpbiBwaHlzaWNhbCBzaXplLiBUaGlzIGluZGljYXRlcyB0aGF0IGFsdGhvdWdoIHN0dWRlbnQgYW5kIHRlYWNoZXIgY29ubmVjdGlvbnMgYXJlIGd1YXJhbnRlZWQsIG9yIGl0IGlzIGd1YXJhbnRlZWQgZm9yIGEgc3R1ZGVudCBub2RlIHRvIGhhdmUgYW4gZWRnZSBjb25uZWN0aW9uIHdpdGggYSB0ZWFjaGVyIG5vZGUsIHRoaXMgZG9lc24ndCBlbnRpcmVseSBtZWFuIHRoYXQgdGVhY2hlcnMgYXJlIHRoZSBtb3N0IHBvcHVsYXIuIFRlYWNoZXIgbm9kZXMgdGhlbXNlbHZlcyBhcmVuJ3QgZXZlbiBhY3RpbmcgYXMgYnJpZGdlcyB0byBvdGhlciBjb21tdW5pdGllcyBidXQgcmF0aGVyIHN0aWNrIHRvIHRoZWlyIG93biBzcGVjaWZpYyBncmFkZSAoaS5lLiwgMUEsIDFCKSBjb21tdW5pdGllcy4gDQoNClRoZSBzdHVkZW50IG5vZGVzIHRoYXQgYm9yZGVyIHRoZSBjb21tdW5pdGllcyBhY3QgYXMgdGhlaXIgb3duIGJyaWRnZXMgdGhhdCB0YWxrIHRvIG90aGVyIGNvbW11bml0aWVzLiBUaGlzIGlzIHN1cHBvcnRlZCBieSB0aGVpciBwaHlzaWNhbCBzaXplIGJlaW5nIG5vdGljZWFibHkgYmlnZ2VyIGFzIHNpemUgaXMgYmFzZWQgb24gZGVncmVlLCBhbmQgdGhlIGVkZ2UgY29ubmVjdGlvbnMgYXJlIGRlbnNlIHdoZW4gYXR0YWNoaW5nIHRvIG5vZGVzIGluIG90aGVyIGNvbW11bml0aWVzLiBUaGVyZSdzIHByb2JhYmx5IGEgbG90IG9mIHN0dWRlbnQgY3Jvc3Mgb3ZlciBiZWhhdmlvciBiZWNhdXNlIG9mIHNpbWlsYXIgc2Nob29sIGFjdGl2aXRpZXMgKGkuZS4sIGJyZWFrZmFzdCwgcmVjZXNzLCBsdW5jaCwgbHVuY2ggcmVjZXNzLCBzYW1lIHRlYWNoZXJzIGV2ZXJ5IGdyYWRlLCBleHRyYWN1cnJpY3VsYXJzKS4gSG93ZXZlciwgYWxzbyBjb25zaWRlciB0aGF0IGdyYWRlIFhBIGFuZCBYQiBwcm9iYWJseSBzaGFyZSBzaW1pbGFyIGNsYXNzZXMuIElmIEkgcmVjYWxsIGZyb20gZWxlbWVudGFyeSBzY2hvb2wsIGFsdGhvdWdoIHdlIGhhZCBkaWZmZXJlbnQgdGVhY2hlcnMsIHRoZXJlIHdlcmUgbm9uLW1haW4gc3ViamVjdCBjbGFzc2VzIChpLmUuLCBtdXNpYywgaHVsYSwgYXJ0cywgUC5FLikgd2hlcmUgdGhlIGVudGlyZSBncmFkZSBsZXZlbCB3YXMgaW4gYSBzaW5nbGUgY2xhc3MuIFRoZSBkYXRhIHNldCBpcyBzbWFsbCBlbm91Z2ggdG8gc2hvdyB0aGF0IHRoZXJlIGlzIGFib3V0IDIwIHN0dWRlbnRzIHBlciBjbGFzc3Jvb20gc28gaXQncyBlbnRpcmVseSBwb3NzaWJsZSB0byBoYXZlIGEgam9pbnQgY2xhc3Mgc2Vzc2lvbiB3aXRoIDQwIHN0dWRlbnRzLiBQZXJmZWN0IHdheSB0byBhbGxvdyBzdHVkZW50cyB0byBjcmVhdGUgbW9yZSAiZWRnZXMiIGFuZCBoYXZlIHRoZSBzdHVkZW50cyB0aGF0IGJvcmRlciBjb21tdW5pdGllcyBhY3QgYXMgInBvcHVsYXIiIGtpZHMuIA0KDQoNCmBgYHtyICBlY2hvPUZBTFNFLCBmaWcuYWxpZ249ImNlbnRlciIsIGZpZy5jYXAgPSAiX19fX19fX19fXyJ9DQojIGluY2x1ZGVfZ3JhcGhpY3MoIkltYWdlcy9fX19fX19fX19fIikNCmBgYA0KDQoqKk9ic2VydmF0aW9ucyBhYm91dCBTYWxpZW50IEluZGl2aWR1YWxzIG9yIFBhaXJzKiogDQoNClRoZXJlIGFyZSBjYXNlcyB3aGVyZSB0aGUgZWRnZXMgYXJlIHRoaWNrZXIgdGhhbiB1c3VhbCBpbiB2aXN1YWwgYXBwZWFyYW5jZSBpbmRpY2F0aW5nIHRoYXQgY2VydGFpbiBzdHVkZW50cyBvciBwYWlycyBvZiBzdHVkZW50cyBoYXZlIGEgc3Ryb25nZXIgY29ubmVjdGlvbi4gQmVjYXVzZSB0aGUgd2VpZ2h0cyBhcmUgZGV0ZXJtaW5lZCBieSBkdXJhdGlvbiwgSSB3b3VsZCBhc3N1bWUgdGhlc2Ugc3Ryb25nIGNvbm5lY3Rpb25zIGluZGljYXRlIHRoYXQgdGhlIHN0dWRlbnRzIGFyZSBwcm9iYWJseSByZWFsLWxpZmUgZnJpZW5kcyBhbmQgbm90IGp1c3QgZnJpZW5kcyBhdCBzY2hvb2wgKGkuZS4sIHBsYXkgb3V0c2lkZSBvZiBzY2hvb2wgd2hldGhlciBpdCBiZSByZWFsLWxpZmUgaGFuZ2luZyBvciBnYW1pbmcgb25saW5lKS4gRXNwZWNpYWxseSBpbiB0aGUgdG9wIGJvcmRlciBvZiAxQiBvZiB0aGUgY2xhc3NuYW1lIHZpc3VhbGl6YXRpb24sIHlvdSBjYW4gc2VlIGxvb3BzIGJldHdlZW4gc3R1ZGVudHMgd2l0aCB0aGljayBibHVlIGVkZ2VzLiBUaGVzZSBwcm9iYWJseSBpbmRpY2F0ZSBzdHJvbmcgZnJpZW5kIGdyb3VwcyB3aGljaCBpcyB0ZWNobmljYWxseSBhIGNvbW11bml0eSBvZiB0aGVpciBvd24uIA0KDQpgYGB7ciAgZWNobz1GQUxTRSwgZmlnLmFsaWduPSJjZW50ZXIiLCBmaWcuY2FwID0gIl9fX19fX19fX18ifQ0KIyBpbmNsdWRlX2dyYXBoaWNzKCJJbWFnZXMvX19fX19fX19fXyIpDQpgYGANCg0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQojIyMgSGVybyBDb2FwcGVhcmFuY2UgTmV0d29yaw0KDQpJbiB0aGlzIHNlY3Rpb24gd2UgZXhhbWluZSBhIG5ldHdvcmsgZGVyaXZlZCBmcm9tIHRoZSBNYXJ2ZWwgU29jaWFsIE5ldHdvcmsgTmV0d29ya3Mgb2Ygc3VwZXIgaGVyb2VzLCBjb25zdHJ1Y3RlZCBieSBDZXNjIFJvc3NlbGzDsywgUmljYXJkbyBBbGJlcmljaCwgYW5kIEpvZSBNaXJvIChodHRwOi8vYmlvaW5mby51aWIuZXMvfmpvZW1pcm8vbWFydmVsLmh0bWwpLiBUaGUgb3JpZ2luYWwgbmV0d29yayBjb25uZWN0cyBjb21pYyBib29rIGhlcm9lcyB0byB0aGUgaXNzdWVzIHRoZXkgYXBwZWFyZWQgaW4uIFdlIHdvcmsgd2l0aCBhIHByb2plY3Rpb24gb250byBoZXJvZXMsIHdpdGggbGlua3MgYmV0d2VlbiBoZXJvZXMgd2VpZ2h0ZWQgYnkgdGhlIG51bWJlciBvZiBpc3N1ZXMgdGhleSBjby1hcHBlYXJlZCBpbi4gV2UgYXJlIGludGVyZXN0ZWQgaW4gaWRlbnRpZnlpbmcgYW5kIGludGVycHJldGluZyBzZXZlcmFsIG9mIHRoZSBsYXJnZXN0ICJjb21tdW5pdGllcyIgb2YgaGVyb2VzIGluIHRoaXMgbmV0d29yay4NCg0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQojIyMjIDQuIFByZXBhcmluZyB0aGUgSGVybyBDb2FwcGVhcmFuY2UgTmV0d29yaw0KDQpUaGUgbmV0d29yayBpcyByZWFkIGluIGFuZCBzdW1tYXJpemVkIGJlbG93LiANCg0KYGBge3J9DQpIZXJvZXMgPC0gcmVhZF9ncmFwaCgiTmV0d29ya3MvSGVyby1Db2FwcGVhcmFuY2UtTmV0d29yay5ncmFwaG1sIiwgDQogICAgICAgICAgICAgICAgIGZvcm1hdD0iZ3JhcGhtbCIpDQpzdW1tYXJ5KEhlcm9lcykNCmBgYA0KDQpXZSBjb21wdXRlIHRoZSBMb3V2YWluIGFuZCBJbmZvTWFwIHBhcnRpdGlvbnMgYW5kIGFubm90YXRlIHZlcnRpY2VzIHdpdGggdGhlaXIgcGFydGl0aW9uIG1lbWJlcnNoaXAgYmVsb3cuIFdlIGFsc28gY29tcHV0ZSBub2RlIGNlbnRyYWxpdHkgbWV0cmljcyBvbiB0aGUgZnVsbCBuZXR3b3JrLCB0byBhaWQgaW4gaW50ZXJwcmV0YXRpb24gKGJ5IGNvbXBhcmlzb24gdG8gcGFydGl0aW9uLXNwZWNpZmljIGNlbnRyYWxpdHkgbWV0cmljcyB0byBiZSBjb21wdXRlZCBpbiBHZXBoaSkuIFRoZSByZXN1bHRpbmcgYW5ub3RhdGVkIG5ldHdvcmsgaXMgc2hvd24gYmVsb3cgYW5kIHdyaXR0ZW4gb3V0IGZvciB2aXN1YWxpemF0aW9uIGluIEdlcGhpLiANCg0KYGBge3J9DQogSGVyb2VzLmxvdXZhaW4gICAgIDwtIGNsdXN0ZXJfbG91dmFpbihIZXJvZXMsIHdlaWdodHM9IEUoSGVyb2VzKSR3ZWlnaHQpDQogSGVyb2VzLmluZm9tYXAgICAgIDwtIGNsdXN0ZXJfaW5mb21hcChIZXJvZXMsIGUud2VpZ2h0cyA9IEUoSGVyb2VzKSR3ZWlnaHQpDQogVihIZXJvZXMpJGxvdXZhaW4gIDwtIG1lbWJlcnNoaXAoSGVyb2VzLmxvdXZhaW4pDQogVihIZXJvZXMpJGluZm9tYXAgIDwtIG1lbWJlcnNoaXAoSGVyb2VzLmluZm9tYXApDQogVihIZXJvZXMpJGRlZ3JlZSAgIDwtIGRlZ3JlZShIZXJvZXMpDQogVihIZXJvZXMpJHdkZWdyZWUgIDwtIHN0cmVuZ3RoKEhlcm9lcywgd2VpZ2h0cz1FKEhlcm9lcykkd2VpZ2h0KQ0KIFYoSGVyb2VzKSRwYWdlcmFuayA8LSBwYWdlX3JhbmsoSGVyb2VzKSR2ZWN0b3INCiBzdW1tYXJ5KEhlcm9lcykNCiB3cml0ZV9ncmFwaChIZXJvZXMsIkhlcm8tQ29tbXVuaXRpZXMuZ3JhcGhtbCIsIGZvcm1hdD0iZ3JhcGhtbCIpDQpgYGANCg0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQojIyMjIDUuIEZpbmRpbmcgQ3Jvc3NpbmcgVmVydGljZXMgDQoNCkNyb3NzaW5nIGVkZ2VzIGFyZSBlZGdlcyB0aGF0IGNyb3NzIHBhcnRpdGlvbnMuIFRoZSB2ZXJ0aWNlcyBhdCB0aGUgZW5kcG9pbnQgb2YgdGhlc2UgZWRnZXMgYXJlIG9mIGludGVyZXN0LCBlc3BlY2lhbGx5IGlmIHRoZXkgcGFydGljaXBhdGUgaW4gbWFueSBjcm9zc2luZ3MsIGFzIHRoZXkgbWF5IGJlIGludm9sdmVkIGluIG11bHRpcGxlIGNvbW11bml0aWVzIGJleW9uZCB0aGUgb25lIHRoYXQgdGhlIHBhcnRpdGlvbiBhc3NpZ25lZCB0byB0aGVtLiBCZWxvdyB3ZSBkaXNwbGF5IHRoZSB0b3AgMjAgb2YgdmVydGljZXMgcmFua2VkIGJ5IHRoZSBudW1iZXIgb2YgY3Jvc3NpbmcgZWRnZXMgaW5jaWRlbnQgb24gdGhlbSBpbiBlYWNoIG9mIHRoZSB0d28gcGFydGl0aW9uczogDQoNCmBgYHtyfQ0KIyBEaXNwbGF5IHRoZSB0b3AgMjAgY3Jvc3NpbmcgdmVydGljZXMgYW5kIHRoZSBudW1iZXIgb2YgZWRnZXMgdmlhDQojIHdoaWNoIHRoZXkgY29ubmVjdCB0byBvdGhlcnMgb3V0c2lkZSB0aGVpciBwYXJ0aXRpb24sIGZvciBib3RoDQojIExvdXZhaW4gYW5kIEluZm9tYXAuIEkgc3VnZ2VzdCB0YWtpbmcgdGhlc2Ugc3RlcHMNCg0KIyBDb21wdXRlIGNyb3NzaW5ncyBmb3IgTG91dmFpbiwgc29ydGVkIGRlY3JlYXNpbmcgYnkgY3Jvc3Npbmc6IA0KDQojIENvbXB1dGUgY3Jvc3NpbmdzIGZvciBJbmZvbWFwLCBzb3J0ZWQgZGVjcmVhc2luZyBieSBjcm9zc2luZzogDQoNCiMgRGlzcGxheSBpbiBjb21iaW5lZCB0aWJibGU6IA0KDQoNCiB0aWJibGUoSGVyb19pbl9Mb3V2YWluID0gVihIZXJvZXMpW3NvcnQodGFibGUoVihIZXJvZXMpW2VuZHMoSGVyb2VzLCB3aGljaChjcm9zc2luZyhIZXJvZXMubG91dmFpbiwgSGVyb2VzKSkpXSRpZCksZGVjcmVhc2luZz1UUlVFKVsxOjIwXV0kbGFiZWwsDQogICAgICAgIENyb3NzX0NvdW50X0wgICA9IHNvcnQodGFibGUoVihIZXJvZXMpW2VuZHMoSGVyb2VzLCB3aGljaChjcm9zc2luZyhIZXJvZXMubG91dmFpbiwgSGVyb2VzKSkpXSRpZCksZGVjcmVhc2luZz1UUlVFKVsxOjIwXSwNCiAgICAgICAgSGVyb19pbl9JbmZvbWFwID0gVihIZXJvZXMpW3NvcnQodGFibGUoVihIZXJvZXMpW2VuZHMoSGVyb2VzLCB3aGljaChjcm9zc2luZyhIZXJvZXMuaW5mb21hcCwgSGVyb2VzKSkpXSRpZCksZGVjcmVhc2luZz1UUlVFKVsxOjIwXV0kbGFiZWwsDQogICAgICAgIENyb3NzX0NvdW50X0kgICA9IHNvcnQodGFibGUoVihIZXJvZXMpW2VuZHMoSGVyb2VzLCB3aGljaChjcm9zc2luZyhIZXJvZXMuaW5mb21hcCwgSGVyb2VzKSkpXSRpZCksIGRlY3JlYXNpbmc9VFJVRSlbMToyMF0NCiApDQpgYGANCg0KX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fDQojIyMjIDYuIEludGVycHJldGluZyBDb21tdW5pdGllcyBpbiBHZXBoaSANCg0KIyMjIyMgKGEpIFZpc3VhbGl6YXRpb24gaW4gR2VwaGkgDQoNClRoZSBuZXR3b3JrIGhhcyBiZWVuIHJlYWQgaW50byBHZXBoaSBhbmQgYSBzcGF0aWFsaXplZCB2aXN1YWxpemF0aW9uIGhhcyBiZWVuIGNvbnN0cnVjdGVkLCBidXQgaXMgdG9vIGNvbXBsZXggdG8gc2hvdyBoZXJlLiBFeGNlcnB0cyB3aWxsIGJlIHRha2VuIGFzIG5lZWRlZCB0byBpbGx1c3RyYXRlIHRoZSBmb2xsb3dpbmcgaW50ZXJwcmV0YXRpb25zIG9mIHBhcnRpdGlvbnMuIA0KDQpgYGB7cn0NCndyaXRlX2dyYXBoKEhlcm9lcywgZmlsZT0iTmV0d29ya3MvSGVyby1Db2FwcGVhcmFuY2UtTmV0d29yay5ncmFwaG1sIixmb3JtYXQgPSAiZ3JhcGhtbCIpDQoNCmBgYA0KDQojIyMjIyAoYikgUGFydGl0aW9ucyBvZiBJbnRlcmVzdA0KDQpUaGUgZm9sbG93aW5nIHBhcnRpdGlvbnMgaGF2ZSBjbGVhciBpbnRlcnByZXRhdGlvbnMgaW4gdGVybXMgb2YgdGhlIGNvbWljIGhlcm8gInVuaXZlcnNlIiwgYW5kIHRoZXJlYnkgaWxsdXN0cmF0ZSB0aGUgcG93ZXIgb2YgY29tbXVuaXR5IGRldGVjdGlvbiBtZXRob2RzIGZvciBmaW5kaW5nIG1lYW5pbmdmdWwgc3ViZ3JhcGhzIGJhc2VkIG9uIHN0cnVjdHVyYWwgaW5mb3JtYXRpb24gYWxvbmUuIA0KDQpUaGUgdmlzdWFsaXphdGlvbiB3YXMgZGlmZmljdWx0IGJ1dCBJIGZpbHRlcmVkIG91dCBlbm91Z2ggdGhpbmdzIHRvIGZpbmQgMyBjb21tdW5pdGllcyB3aGljaCBhcmUgcHJvYmFibHkgdGhlIG1vc3Qgbm90YWJsZSBhbmQgY2VudHJhbC4gVGhpcyBmaWd1cmUgd2FzIG1hZGUgYnkgc2V0dGluZyBub2RlIHNpemUgdG8gZWlnZW52ZWN0b3IgY2VudHJhbGl0eSwgY29sb3JpbmcgYnkgaW5mb21hcCBhbmQgY2hvb3NpbmcgMTAgYXJiaXRyYXJ5IGNvbG9ycy4gSSB0aGVuIHNldCBldmVyeXRoaW5nIHRoYXQgaXNuJ3QgdGhlIGJpZyAzIGNvbW11bml0aWVzIHRvIHdoaXRlIGFuZCBmaWx0ZXJlZCBieSBwYXJ0aXRpb24gaW5mb21hcC4gDQoNCmBgYHtyICBlY2hvPUZBTFNFLCBmaWcuYWxpZ249ImNlbnRlciIsIGZpZy5jYXAgPSAiVGhlIEJpZyAzIn0NCiBpbmNsdWRlX2dyYXBoaWNzKCJJbWFnZXMvY29taWMucG5nIikNCmBgYA0KDQoqKkZpcnN0IFBhcnRpdGlvbioqIA0KDQpUaGlzIGZpZ3VyZSB3YXMgbWFkZSBieSBzZXR0aW5nIG5vZGUgc2l6ZSB0byBlaWdlbnZlY3RvciBjZW50cmFsaXR5LCBjb2xvcmluZyBieSBpbmZvbWFwIGFuZCBjaG9vc2luZyAxMCBhcmJpdHJhcnkgY29sb3JzLiBJIHRoZW4gc2V0IGV2ZXJ5dGhpbmcgdGhhdCBpc24ndCB0aGUgYmlnIDMgY29tbXVuaXRpZXMgdG8gd2hpdGUgYW5kIGZpbHRlcmVkIGJ5IHBhcnRpdGlvbiBpbmZvbWFwLiANCg0KRm9yIHRoaXMgcGFydGljdWxhciBwYXJ0aXRpb24gd2l0aCBpbmZvbWFwIGNvbG9yZWQgaW4gcGluaywgd2Ugc2VlIGEgY29tbXVuaXR5IG9mIGdlbmVyYWwgIm1haW4iIG1hcnZlbCB2aWxsYWlucy4gVGhpcyBpcyBzdXBwb3J0ZWQgYnkgdGhlIGZhY3Qgd2Ugc2VlIHJlcGVhdGluZyB0aXRsZXMgb2YgIltpbnNlcnQgbWFydmVsIGNoYXJhY3RlciBuYW1lXSBEb3BwZWxnYW5nZXIiLiBJbiB0aGUgY29taWNzIHRoZXJlIHdlcmUgYSBsb3Qgb2YgY2xvbmUgc3RvcmllcyB3aGVyZSB0aGUgY2hhcmFjdGVycyBoYXZlIHRvIGZhY2UgdGhlbXNlbHZlcy4gVG93YXJkcyB0aGUgbWlkZGxlIHJpZ2h0IG9mIHRoZSBmaWd1cmUgd2Ugc2VlIHBvcHVsYXIgdmlsbGFpbnMgc3VjaCBhcyBUaGFub3MsIEdhbGFjdHVzLCBEZWF0aCwgYW5kIGZ1cnRoZXIgZG93biB3ZSBjYW4gc2VlIFN1cmZlci4gVGhlc2UgYXJlIGFsbCBtYXJ2ZWwgY2hhcmFjdGVycyB0aGF0IGhhdmUgcHJvbWluZW50IGNhbWVvcyBpbiB0aGUgbWFydmVsIGNpbmVtYXRpYyB1bml2ZXJzZSBhcyB2aWxsYWlucyBhcyB3ZWxsLiANCg0KYGBge3IgIGVjaG89RkFMU0UsIGZpZy5hbGlnbj0iY2VudGVyIiwgZmlnLmNhcCA9ICJBdmVuZ2VycyBWaWxsYWlucyJ9DQogaW5jbHVkZV9ncmFwaGljcygiSW1hZ2VzL21hcnZlbHZpbGxhbi5wbmciKQ0KYGBgDQoNCioqU2Vjb25kIFBhcnRpdGlvbioqIA0KDQpUaGlzIGZpZ3VyZSB3YXMgbWFkZSBieSBzZXR0aW5nIG5vZGUgc2l6ZSB0byBlaWdlbnZlY3RvciBjZW50cmFsaXR5LCBjb2xvcmluZyBieSBpbmZvbWFwIGFuZCBjaG9vc2luZyAxMCBhcmJpdHJhcnkgY29sb3JzLiBJIHRoZW4gc2V0IGV2ZXJ5dGhpbmcgdGhhdCBpc24ndCB0aGUgYmlnIDMgY29tbXVuaXRpZXMgdG8gd2hpdGUgYW5kIGZpbHRlcmVkIGJ5IHBhcnRpdGlvbiBpbmZvbWFwLiANCg0KSW4gdGhpcyBwYXJ0aWN1bGFyIHBhcnRpdGlvbiBjb2xvcmVkIGluIHJlZCwgd2Ugc2VlIGV2aWRlbmNlIHRoYXQgdGhlc2UgY2hhcmFjdGVycyBhcmUgbWFpbiBtZW1iZXJzIG9mIE1hcnZlbCBBdmVuZ2VycyBvciBoZWF2aWx5IHJlbGF0ZWQgdG8gdGhlIEF2ZW5nZXJzIHdpdGggbm90YWJsZSBuYW1lcyBzdWNoIGFzIFNjYXJsZXQgV2l0Y2gsIFZpc2lvbiwgSGF3aywgSXJvbiBNYW4sICwgQ2FwdGFpbiBBbWVyaWNhLCBIdWxrLCBXYXNwLCBRdWlja3NpbHZlciwgSmFydmlzLCBldGMuIA0KDQpgYGB7ciAgZWNobz1GQUxTRSwgZmlnLmFsaWduPSJjZW50ZXIiLCBmaWcuY2FwID0gIkF2ZW5nZXJzIn0NCiBpbmNsdWRlX2dyYXBoaWNzKCJJbWFnZXMvYXZlbmdlcnMucG5nIikNCmBgYA0KDQoqKlRoaXJkIFBhcnRpdGlvbioqIA0KDQpUaGlzIGZpZ3VyZSB3YXMgbWFkZSBieSBzZXR0aW5nIG5vZGUgc2l6ZSB0byBlaWdlbnZlY3RvciBjZW50cmFsaXR5LCBjb2xvcmluZyBieSBpbmZvbWFwIGFuZCBjaG9vc2luZyAxMCBhcmJpdHJhcnkgY29sb3JzLiBJIHRoZW4gc2V0IGV2ZXJ5dGhpbmcgdGhhdCBpc24ndCB0aGUgYmlnIDMgY29tbXVuaXRpZXMgdG8gd2hpdGUgYW5kIGZpbHRlcmVkIGJ5IHBhcnRpdGlvbiBpbmZvbWFwLiANCg0KVGhpcyBvbmUgSSBnb3QgbHVja3kuIEkgcmVhZCBzb21lIGNvbWljcyBhbmQgd2F0Y2hlZCB0aGUgb3JpZ2luYWwgRmFudGFzdGljIDQgbW92aWVzIHRvIGltbWVkaWF0ZWx5IGtub3cgdGhlIGNoYXJhY3RlciBuYW1lcyByaWdodCB1bmRlciB0aGUgcHJldmlvdXMgdHdvIGNvbW11bml0aWVzLiBCYXNlZCBvbiB0aGUgbmFtZXMsIHdlIHNlZSBldmlkZW5jZSB0aGF0IHRoaXMgY29tbXVuaXR5IGlzIGJhc2VkIG9uIHRoZSBGYW50YXN0aWMgNCBzdG9yeWxpbmUvc2VyaWVzIChpLmUuLCBEci4gRG9vbSwgSW52aXNpYmxlIFdvbWFuLCBIdW1hbiBUb3JjaCwgTXIuIEZhbnRhc3RpYywgVGhpbmcsIGV0Yy4pDQoNCmBgYHtyICBlY2hvPUZBTFNFLCBmaWcuYWxpZ249ImNlbnRlciIsIGZpZy5jYXAgPSAiRmFudGFzdGljIDQifQ0KIGluY2x1ZGVfZ3JhcGhpY3MoIkltYWdlcy9mYW50YXN0aWM0LnBuZyIpDQpgYGANCg0KDQojIyMjIyAoYykgSW1wbGljYXRpb25zIG9mIENyb3NzaW5nIFZlcnRpY2VzDQoNCkNvbXBhcmluZyB0aGUgaGlnaC1jZW50cmFsaXR5IChpbXBvcnRhbnQpIGhlcm8gZmlndXJlcyBpbiB0aGUgYWJvdmUgcGFydGl0aW9ucyB0byB0aGUgY3Jvc3NpbmcgdmVydGljZXMgYW5hbHlzaXMgcGVyZm9ybWVkIHByZXZpb3VzbHksIHdlIHNlZSB0aGF0IG1hbnkgaGVyb2VzIGNlbnRyYWwgaW4gYSBzaW5nbGUgcGFydGl0aW9uIGFyZSBhbHNvIGhpZ2ggb24gdGhlIGNyb3NzaW5nIHZlcnRpY2VzIGxpc3QuIA0KDQpUaGlzIGZhY3Qgc3VnZ2VzdHMgdGhhdCBpbiB0aGUgY29taWMgdW5pdmVyc2UsIHRoZXNlIGhlcm9lcyBhbmQgdmlsbGFpbnMgYWxpa2UsIHBsYXkgYSByb2xlIGluIGNvbW11bml0aWVzIGFuZCBzdWIgY29tbXVuaXRpZXMuIE91ciBpbmZvbWFwIGludGVycHJldGF0aW9uIG9mIHRoZSBjb21pYyBib29rIGRhdGEgc2V0IHNob3dzIHRoYXQgYWx0aG91Z2ggdGhlc2UgY2hhcmFjdGVycyBoYXZlIGEgbWFpbiBjb21tdW5pdHkgdGhleSBwYXJ0aWNpcGF0ZSBpbiwgbm90YWJseSBNYXJ2ZWwgdmlsbGFpbnMsIE1hcnZlbCBBdmVuZ2VycywgYW5kIEZhbnRhc3RpYyA0LCBpdCBkb2Vzbid0IG5lY2Vzc2FyaWx5IG1lYW4gdGhleSBhcmUgcmVzdHJpY3RlZCB0byB0aGVpciBvd24gY29tbXVuaXR5LiBBbG90IG9mIGNoYXJhY3RlcnMgY3Jvc3Mgb3ZlciB0aGVtc2VsdmVzIGFzIHRlYW0gbWVtYmVycyBvciB2aWxsYWlucyB3aXRoIGNvbWljIGlzc3VlcyB0aGF0IGhhdmUgdG8gcHJvdmlkZSBmcmVzaCBwbG90IGxpbmVzLCBjcm9zcyBvdmVyIHBsb3QgbGluZXMsIGRhcmsgcGxvdCBsaW5lcywgZmFuIHNlcnZpY2UsIG11bHRpLXZlcnNlIHBsb3QgbGluZXMsIHRpbWUgdHJhdmVsIHBsb3QgbGluZXMsIGFuZCB0aGUgaW5mYW1vdXMgY2FwY29tIHZzIG1hcnZlbCBzZXJpZXMuIFRoZSBjcm9zc2luZyBlZGdlcyBhbmQgY3Jvc3NpbmcgdmVydGljZXMgaXMgYW4gaW5kaWNhdGlvbiBvZiB0aGF0LiANCg0KSXQgYWxzbyBzdWdnZXN0cyBhIGxpbWl0YXRpb24gb2YgdGhlIGFib3ZlIGNvbW11bml0eSBkZXRlY3Rpb24gbWV0aG9kczogVGhlc2UgY29tbXVuaXR5IGRldGVjdGlvbiBtZXRob2RzIG9ubHkgc2hvdyBzdXJmYWNlIGxldmVsIGNvbW11bml0aWVzIGFuZCBkb2Vzbid0IHNob3cgdGhlIGludHJpY2F0ZSBkZXRhaWxzIGFuZCBjcm9zcyBvdmVyIHBsb3QgbGluZXMgd3JpdHRlbiBieSB0aGUgY29taWMgYm9vayB3cml0ZXJzIGFuZCBhcnRpc3RzIGFzIGEgbG90IG9mIGNoYXJhY3RlcnMgaW4gbXkgdmlzdWFsaXphdGlvbiBwcm9iYWJseSBoYXMgYW4gdW5kZXRlY3RlZCBjb21tdW5pdHkgKGNvbWljIHNlcmllcykgd2l0aCBhIHJpY2ggcGxvdCBsaW5lIHNob3dpbmcgdGhhdCB0aGV5IHdlcmUgaW4gZmFjdCBhcGFydCBvZiBhIHdob2xlIGRpZmZlcmVudCBzZXQgb2YgY29tbXVuaXRpZXMuIA0KDQpfX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX19fX18NCiMjIyBQYXUgDQo=